POSTing / Uploading Files using the WCF Web API

Written on July 27, 2011

Disclaimer: I know that there are things like FTP Winking smile

In one of my projects I need to transfer files from my WPF-Application to a server which is only available through HTTP.

Lets solve this using WCF Web API and it's HttpClient:

Files are received by a resource method called "Upload"

[WebInvoke(Method = "POST", UriTemplate = "{filename}")]
public HttpResponseMessage Upload(string filename, HttpRequestMessage request) {

    // grab the posted stream
    Stream stream = request.Content.ContentReadStream;

    // write it to 
    using (FileStream fileStream = File.Create(string.Format(@"c:\projects\step\{0}", filename), (int)stream.Length)) {
        byte[] bytesInStream = new byte[stream.Length];
        stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
        fileStream.Write(bytesInStream, 0, bytesInStream.Length);
    }

    // http house keeping
    return new HttpResponseMessage(HttpStatusCode.Created, "");
}

The client POSTs the file:

HttpClient client = new HttpClient("http://localhost:52046/");

// enable support for files up to 10 MB size
HttpClientChannel channel = 
    new HttpClientChannel() { MaxRequestContentBufferSize = 1024 * 1024 * 10 };
client.Channel = channel;

FileStream file = new FileStream(_path, FileMode.Open);
StreamContent fileContent = new StreamContent(file);

string fileName = Path.GetFileName(_path);
client.Post(string.Format("file/{0}",fileName), fileContent);

This has been straight forward. Now we need to enable Streaming and receiving files greater than 64KB on the Server.

This is done by configuring the endpoint.

To be able to access the HttpEndpoint for our URI in the global.asax (when IIS hosting it), we need to implement a custom HttpConfigurableServiceHostFactory:

public class CustomServiceHostFactory : HttpConfigurableServiceHostFactory {
    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses) {
        var host = base.CreateServiceHost(constructorString, baseAddresses);

        foreach (HttpEndpoint endpoint in host.Description.Endpoints) {
            endpoint.TransferMode = TransferMode.Streamed;
            endpoint.MaxReceivedMessageSize = 1024 * 1024 * 10;
        }

        return host;
    }
}

To get it up and running, we need to assign it to our route definition for the resource handling our uploads:

RouteTable.Routes.MapServiceRoute<StepFileResource,CustomServiceHostFactory>("file",null,null);

Thanks to Pedro for helping me out of the configuration hell ;-)

...and by the way: Happy uploading with WCF Web API!

DotNetKicks-DE Image