Reading file input from a multipart/form-data POST

rafale picture rafale · Sep 18, 2011 · Viewed 140.7k times · Source

I'm POSTing a file to a WCF REST service through a HTML form, with enctype set to multipart/form-data and a single component: <input type="file" name="data">. The resulting stream being read by the server contains the following:

------WebKitFormBoundary
Content-Disposition: form-data; name="data"; filename="DSCF0001.JPG"
Content-Type: image/jpeg

<file bytes>
------WebKitFormBoundary--

The problem is that I'm not sure how do extract the file bytes from the stream. I need to do this in order to write the file to the disk.

Answer

Ohad Schneider picture Ohad Schneider · Feb 10, 2014

Sorry for joining the party late, but there is a way to do this with Microsoft public API.

Here's what you need:

  1. System.Net.Http.dll
    • Included in .NET 4.5
    • For .NET 4 get it via NuGet
  2. System.Net.Http.Formatting.dll

Note The Nuget packages come with more assemblies, but at the time of writing you only need the above.

Once you have the assemblies referenced, the code can look like this (using .NET 4.5 for convenience):

public static async Task ParseFiles(
    Stream data, string contentType, Action<string, Stream> fileProcessor)
{
    var streamContent = new StreamContent(data);
    streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType);

    var provider = await streamContent.ReadAsMultipartAsync();

    foreach (var httpContent in provider.Contents)
    {
        var fileName = httpContent.Headers.ContentDisposition.FileName;
        if (string.IsNullOrWhiteSpace(fileName))
        {
            continue;
        }

        using (Stream fileContents = await httpContent.ReadAsStreamAsync())
        {
            fileProcessor(fileName, fileContents);
        }
    }
}

As for usage, say you have the following WCF REST method:

[OperationContract]
[WebInvoke(Method = WebRequestMethods.Http.Post, UriTemplate = "/Upload")]
void Upload(Stream data);

You could implement it like so

public void Upload(Stream data)
{
    MultipartParser.ParseFiles(
           data, 
           WebOperationContext.Current.IncomingRequest.ContentType, 
           MyProcessMethod);
}