Wednesday, May 16, 2018

ASP.NET WebAPI2 multipart/formdata upload error

If the following error looks familiar please check the info below !


Error writing MIME multipart body part to output stream
System.IO.IOException

According to the internet it can have many reasons, in my case it was a simple semicolon. 

The problem is actually in the client code. It is a semicolon after the form data !
i marked it red ! if it's in the code the servers throws an exception at:

  • await Request.Content.ReadAsMultipartAsync(provider);

if you remove it it works perfectly. other server implementation don't have a problem with the semicolon.....

UseCases:


  • C# Client to upload files and formdata
  • C# Self hostet WebApi2 rest server
Client code:
---------------------------------------------------------------------------------------

       private static string UploadFiles(string url, NameValueCollection values, NameValueCollection files = null)
        {
            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
            // The first boundary
            byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            // The last boundary
            byte[] trailer = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            // The first time it itereates, we need to make sure it doesn't put too many new paragraphs down or it completely messes up poor webbrick
            byte[] boundaryBytesF = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");

            try
            {
                // Create the request and set parameters
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.ContentType = "multipart/form-data; boundary=" + boundary;
                request.Method = "POST";
                request.KeepAlive = true;
                request.SendChunked = true;


                // Get request stream
                Stream requestStream = request.GetRequestStream();

                foreach (string key in values.Keys)
                {
                    // Write item to stream
                    byte[] formItemBytes =              System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}", key, values[key]));
                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    requestStream.Write(formItemBytes, 0, formItemBytes.Length);
                }

                if (files != null)
                {
                    foreach (string key in files.Keys)
                    {
                        if (File.Exists(files[key]))
                        {
                            int bytesRead = 0;
                            byte[] buffer = new byte[2048];
                            string filename = new FileInfo(files[key]).Name;
                            byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", key, filename));
                            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                            requestStream.Write(formItemBytes, 0, formItemBytes.Length);

                            using (FileStream fileStream = new FileStream(files[key], FileMode.Open, FileAccess.Read))
                            {
                                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                                {
                                    // Write file content to stream, byte by byte
                                    requestStream.Write(buffer, 0, bytesRead);
                                }

                                fileStream.Close();
                            }
                        }
                    }
                }

                // Write trailer and close stream
                requestStream.Write(trailer, 0, trailer.Length);
                requestStream.Close();

                using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
                {
                    return reader.ReadToEnd();
                };

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return "";
        }

Server Code:
--------------------------------------------------------------------------------------------------------------
public class UploadController : UtilityController
{      
        [HttpPost]
        public async Task PostFormData()
        {
            // Check if the request contains multipart/form-data.
            if (!Request.Content.IsMimeMultipartContent())
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
            }

            string root = Parameters.Get("UploadPath", Path.GetTempPath().EnsureBS(), "Files");
            var provider = new MultipartFormDataStreamProvider(root);

            try
            {
                // throws exception next line !!!!
                await Request.Content.ReadAsMultipartAsync(provider);

                // This illustrates how to get the file names.
                foreach (MultipartFileData file in provider.FileData)
                {
                    Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                    Trace.WriteLine("Server file path: " + file.LocalFileName);
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (System.Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
            }
        }
}

No comments:

Post a Comment