I've been writing a .NET client application that must upload a file to a IBM WebSphere (Java) server. This journey was met with mis-steps all over the place. For starters, it looked like the WebClient class was what I wanted, but it turns out you can't POST both a file and HTML form variables. That meant that I needed to go to the low-level class, HttpWebRequest, to get this done. There is code on google that got me most of the way there, but the web server always ended up rejecting the submission with errors. To make matters worse, I don't own the web server, so support on exactly what was wrong was extremely limited.
Then I stumbled across a paper, Retrieving HTTP content in .NET by Rick Strahl. In that paper, Rick ends up writing a very nice wrapper class to deal with all of the details for you. I put together a test case to try this out, and the amount of code I had to write dropped from 123 lines down to 15. The new code even works with WebSphere. What's more, the wrapper class provides a very nice model for programming applications that need to communicate via HTTP. In my opinion, this is what Microsoft should have delivered with the framework, as opposed to making people write their own wrapper or find Rick's code (which was last updated in 2002, yet still works great).
I made 2 changes to Rick's base class:
- I changed the cMultiPartBoundary variable to look like this in order to give a unique boundary marker: string cMultiPartBoundary = "-----------------------------" + DateTime.Now.Ticks.ToString("x");
- In the method GetUrlStream, there is a place where the end boundary marker is written to the stream. However, according to the RFC on uploading files via POST, you need to have 2 trailing dashes to mark the last end. I added those dashes like this: this.oPostData.Write(Encoding.GetEncoding(1252).GetBytes( "--" + this.cMultiPartBoundary + "--\r\n" ) );
I am one happy camper. I've done this very thing with other web applications in Delphi before, and with the Indy components, it was very easy. Now with Rick's wrapper class, it's easy to do the same kind of thing in .NET.