Saturday, 31 October 2009

Parsing Multipart Form Data in a WCF Service

Recently I needed a web page that uploaded files directly to a Windows Communication Foundation (WCF) service. On the face of it this seemed achievable: plonk a file upload field on my web page, and write a WCF service that accepts a file Stream.

So I did this, and it sort of worked - however the file that arrived on my server was all garbled! Then I remembered that a browser does not just post the binary contents of a file, it posts "multipart form data" which can include any other field data included in the form.

SURELY there is some sort of low-level .NET API that can read multipart form data, and just give me my file stream...right? Well I bet somewhere there is, but I couldn't find anything that I could use within a WCF service. Ugh.

So I'm left to deal with it myself. By inspecting the contents of the multipart data, I get something like this:

Content-Disposition: form-data; name=\"Filename\"

Content-Disposition: form-data; name=\"Filedata\"; filename=\"PB020344.jpg\"
Content-Type: application/octet-stream

Content-Disposition: form-data; name=\"Upload\"

Submit Query

The binary data starts after the Content-Type, and ends with a line break. So I wrote a parsing class that uses some regular expressions to extract the binary data. It also retrieves the posted file name, and the content type.

Download from CodePlex

It works great in my scenario, however there may be scenarios where it will fail - for example posting multiple files in a single form.

To use the class in a WCF service, your implementation would look something like this:

public string Upload(Stream stream)
    MultipartParser parser = new MultipartParser(stream);

        // Save the file
        SaveFile(parser.Filename, parser.ContentType, parser.FileContents);
        throw new WebException(System.Net.HttpStatusCode.UnsupportedMediaType, "The posted file was not recognised.");



Anonymous said...


Yous parser works great. Is creating the file fine.

How can I get the rest of the data from the post?


Anthony said...

I guess you'd need to parse the stream to get the additional data - my component doesn't support this at the moment.

If you wanted to have a stab at this yourself, my code currently converts the stream into a string. It would then be a matter of splitting the form data into key/value pairs (e.g. into a Dictionary object).


Lukasz said...

Thanks Anthony,
It's very useful :)