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:
------------cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5 Content-Disposition: form-data; name=\"Filename\" PB020344.jpg ------------cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5 Content-Disposition: form-data; name=\"Filedata\"; filename=\"PB020344.jpg\" Content-Type: application/octet-stream BINARY DATA IS HERE ------------cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5 Content-Disposition: form-data; name=\"Upload\" Submit Query ------------cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5--
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); if(parser.Success) { // Save the file SaveFile(parser.Filename, parser.ContentType, parser.FileContents); } else { throw new WebException(System.Net.HttpStatusCode.UnsupportedMediaType, "The posted file was not recognised."); } }
Cheers,
Anthony.
3 comments:
Anthony,
Yous parser works great. Is creating the file fine.
How can I get the rest of the data from the post?
Thanks.
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).
Anthony.
Thanks Anthony,
It's very useful :)
Post a Comment