Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading file input from a multipart/form-data POST

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.

like image 597
rafale Avatar asked Sep 18 '11 07:09

rafale


People also ask

How do I upload a file with multipart form data?

Follow this rules when creating a multipart form: Specify enctype="multipart/form-data" attribute on a form tag. Add a name attribute to a single input type="file" tag. DO NOT add a name attribute to any other input, select or textarea tags.

How do I pass a multipart file in curl?

With curl, you add each separate multipart with one -F (or --form ) flag and you then continue and add one -F for every input field in the form that you want to send.

How does multipart file upload work?

Multipart upload allows you to upload a single object as a set of parts. Each part is a contiguous portion of the object's data. You can upload these object parts independently and in any order. If transmission of any part fails, you can retransmit that part without affecting other parts.


2 Answers

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
    • For .NET 4.5 get this NuGet package
    • For .NET 4 get this NuGet package

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); } 
like image 200
Ohad Schneider Avatar answered Sep 28 '22 05:09

Ohad Schneider


You may take a look at the following blog post which illustrates a technique that could be used to parse multipart/form-data on the server using the Multipart Parser:

public void Upload(Stream stream) {     MultipartParser parser = new MultipartParser(stream);     if (parser.Success)     {         // Save the file         SaveFile(parser.Filename, parser.ContentType, parser.FileContents);     } } 

Another possibility is to enable aspnet compatibility and use HttpContext.Current.Request but that's not a very WCFish way.

like image 20
Darin Dimitrov Avatar answered Sep 28 '22 05:09

Darin Dimitrov