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:
BoundaryDelimiter = "---------------------"
Now the problem with your code is that you are missing a couple of dashes (--
) when calculating your boundary delimiters in order to conform to RFC2388
.
So instead of:
BeginContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "\r\n");
EndContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "--\r\n");
You need this:
BeginContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + "--" + Boundary + "\r\n");
EndContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + "--" + Boundary + "--\r\n");
Notice the additional --
that I have added to your begin and end content boundary delimiters.
Check the example provided here
:
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
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:
request.ContentLength = ContentLenght
This will simplify your code as the HttpWebRequest
class will automatically populate the Content-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 of HttpWebRequest
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.