I'm trying to send a Multipart request to a Web API using HttpWebRequest
. The request I'm sending has the following format:
----------636194206488346738
Content-Disposition: form-data; name="file"; filename="A.png"
Content-Type:application/octet-stream
Content-Transfer-Encoding: binary
{Binary data in here}
----------636194206488346738--
{new line at the end}
And the request configuration is as follows:
Content-Type:"multipart/form-data; boundary=----------636194206488346738
Method: POST
Keep-Alive: True
When sending the request to the web API I get the Invalid end of stream error
. However, I tried to convert the stream to text to see the actual data and it matches the example I added above.
However, when I'm using the WebClient
and call the UploadFile
method for the same purpose, I can successfully upload files to the API without any problem suggesting that something is wrong with my approach which is as follows.
My Constants:
Boundary = DateTime.Now.Ticks.ToString();
ContentType = "multipart/form-data; boundary=" + BoundaryDelimiter + Boundary;
BeginContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "\r\n");
EndContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "--\r\n");
Method for formatting form data:
private Byte[] FormDataFormat(String name, String fileName, String contentType)
=> System.Text.Encoding.UTF8.GetBytes(String.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type:{2}\r\nContent-Transfer-Encoding: binary\r\n\r\n", name, fileName, contentType));
Attaching file to a stream:
Stream = new MemoryStream();
foreach (var i in files) {
var tempEncode = FormDataFormat("file", i, "application/octet-stream");
var file = System.IO.File.ReadAllBytes(i); // Files are supposed to be small.
Stream.Write(BeginContent, 0, BeginContent.Length);
Stream.Write(tempEncode, 0, tempEncode.Length);
Stream.Write(file, 0, file.Length);
ContentLenght += BeginContent.Length + tempEncode.Length + file.Length;
}
Stream.Write(EndContent, 0, EndContent.Length);
ContentLenght += EndContent.Length;
Creating the request:
public HttpWebRequest Request(String method) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ContentType = ContentType;
request.KeepAlive = true;
request.Method = method;
request.ContentLength = ContentLenght;
Stream.Seek(0, SeekOrigin.Begin);
Stream.CopyTo(request.GetRequestStream());
Stream.Dispose();
return request;
}
You haven't shown in your question the
BoundaryDelimiter
variable declaration but for the purpose of this answer I will assume that it is defined like this:Now the problem with your code is that you are missing a couple of dashes (
--
) when calculating your boundary delimiters in order to conform toRFC2388
.So instead of:
You need this:
Notice the additional
--
that I have added to your begin and end content boundary delimiters.Check the example
provided here
:Notice how the boundary is equal to
AaB03x
but the delimiter is actually--AaB03x
and of course the end delimiter is--AaB03x--
.As a side note you could get rid of the
ContentLenght
variable (which you have misspelled by the way :-)) and remove this line:This will simplify your code as the
HttpWebRequest
class will automatically populate theContent-Length
header depending on the number of bytes you have written to the request stream.This being said, I would recommend you using the
HttpClient
class instead ofHttpWebRequest
because it already has built-in capabilities for properly encoding this kind of stuff. It will definitely make your code more readable as you will not have to worry about boundaries, delimiters and content lengths.