Transferring large files using WCF

Recently I wanted to send large files (several GB) from a rich desktop client to a web service. The client and service communicate using WCF and I thought that this would be quite easy. As it turns out it is but there are a few gotchas on the way.


The first gotcha is that you do not want to buffer the message as you send it. Depending on the amount of RAM and the size of the file this may or may not be a problem on the client but it’s almost certainly going to be a problem on the server with multiple clients sending files at the same time.

To solve this you can either write a service contract that accepts the file in chunks or use WCF streaming. In this instance I decided to use streaming.

Streaming in WCF does have some drawbacks which I’m not going to go into here so it’s not suitable for everything but it was fine in this situation.

To use streaming you simply pass parameters of type ‘Stream’ and change the config to use streaming. This is a per endpoint setting so I set up a separate endpoint for the upload service.

Passing Metadata

The next problem I found was how to pass metadata with streams. Since I’m uploading via HTTP I want to make sure the file gets there intact so I’d like to transfer a checksum with the file (along with other details). WCF will not let you have any other parameters if using streams so how do you pass it.

Since using sessions with streaming can result in unpredictable behaviour there are a couple of options open. The first is to return a GUID (or other unique ID) after uploading the file and then allow a separate operation to set the metadata for that GUID and then link it to the previous file upload.The other option, and the one I chose, is to explicitly specify the message and send the metadata in the message header.

Max Message Sizes

The next issue I faced was the size of the messages, you need to ensure that the maxReceivedMessageSize is set large enough for your largest file. Since headers are always buffered, even when streaming, you want to ensure that this doesn’t result in DOS attacks by settings maxBufferSize to something reasonable such as 64K. This will allow large streamed bodies but limits the size of the headers.


So that’s it, all set up and working now. Well not quite. As I mentioned at the start there are a few gotchas with this.

First, the VS webdev server (Cassini) cannot handle streaming over HTTP. This is simple to fix, use IIS or self host in a console app or windows service.

Second, IIS uses the ASP.NET maxRequestLength setting for the max length not the WCF setting. You need to add this to your web config.

Third, IIS cannot transfer more than 2GB of data. You’ll need to self host to get around this if you need to send more data than that.

Fourth, timeouts can occur so you need to increase the send/receive timeouts in WCF.


So here are samples of the code bits I used.

web.config – server

    <httpRuntime maxRequestLength="2097151" />

    <binding name="FileSenderService.StreamedBinding"
                 transferMode="StreamedRequest" maxBufferSize="65536"
                 maxReceivedMessageSize="2000000000" messageEncoding="Mtom"


app.config – client

    <binding name="BasicHttpBinding_IFileTransfer" sendTimeout="00:10:00"
             messageEncoding="Mtom"transferMode="StreamedRequest" />


public class SendFileRequestMessage
    [MessageHeader(MustUnderstand = true)]
    public FileTransferInfo FileInfo;

    [MessageBodyMember(Order = 1)]
    public Stream FileData;

public interface IFileTransfer
    void SendFile(SendFileRequestMessage request);

public class FileTransferInfo
    [DataMember(Order = 1, IsRequired = true)]
    public string Name { get; set; }

    [DataMember(Order = 2, IsRequired = true)]
    public byte[] Checksum { get; set; }

The following blogs / articles were useful in sorting this out.

16 thoughts on “Transferring large files using WCF

  1. Thanks thanks thanks. We need people thats share information (important and easy) with us. So simple, so difficult to find on net ever on MSDN. Thank you again.

  2. Thanks for the comments and glad the article helped you out. I really must start posting some more snippets like this one.

  3. I am also trying to put together something like this, using the same links as you did as a base framework.

    However, I keep getting an error like the following:

    Operation ‘UploadFile’ in contract ‘IFileTransferService’ uses a MessageContract that has SOAP headers. SOAP headers are not supported by the None MessageVersion.

    I have tried using both basicHttpBinding and a customBinding, but the error is still there.

    Have you faced anything like that while developing your own service?

  4. Thats odd Stefano. It’s quite correct that you can’t use SOAP headers with a message version of None as that enables POX messaging and thus disables SOAP.

    Try explicitly setting the MessageVersion property on the basic HTTP binding to something other than None such as Soap11 to see if that helps. Unfortunately it looks like the basicHttpBindingElement in the configuration file doesn’t expose that property so you’ll probably have to do it in code.

    However, you could also try adding a textMessageEncoding element to your custom binding with a messageVersion attribute of Soap11 as I believe you can do that in config. I’ve not tested any of these things since it all worked ok with what I did above.

  5. I finally found out what the issue was with my service… nothing to do with message version, despite what WCF was trying to tell me. I had simply mispelled the name of one of the classes implementing the service.

    I have posted my experience should any other people incur in the same strange error message:

  6. Hello, I’m trying to do the same thing and every thing works great except that when I send over the service a value in Checksum like this byte[] Checksum = new MD5CryptoServiceProvider().ComputeHash(fstream); the file stream is not sent. Have you face this problem?

  7. I’ve not tried to duplicate your problem yet Armando but if you are using the same stream for the MD5 that you are putting in the message then you may need to reset the position before you use it the second time. If the MD5 class leaves the stream read pointer at the end of the stream I guess WCF might try and read from it and immediately hit end of file. Try either doing an explicit seek to the beginning of the stream or open two streams on the same file. Let me know how that goes and I’ll have another look at it when I get chance.

  8. How can i access the same web service from a web page like from an page, any suggestions on what needs to be done on the page to collect the entire file before writing it down to the client.

    • @Prashant if you are looking to use this mechanism to download directly to a web page via an AJAX style call then that probably isn’t something you’ll be able to easily do. I’ve not tried it but I’d imagine that you’d have problems writing the data anywhere since the JavaScript is sandboxed and you won’t have direct access to the disk to write it.

      Having said that if you have a service like that and you need to download a file from it via a normal web browser you’d want to write a custom HTTP handler or ASP.NET page that connects to the WCF service and pulls the file when requested and then uses a regular HTTP unbuffered download of the content to the browser. This would have to be triggered on the browser as a normal download and would prompt the user for the save location as per any other normal download.

  9. Thanks for your post. Your info is clear and easy to follow.
    I just have a question:

    When i make a call to SendFile(), i’m greeted with a byte[] instead of a SendFileRequestMessage parameter.
    How am i to pack the byte[]? Am i using the correct Stream type?

    Bit confused.

  10. Hi Robert,

    Would like to implement uploading file (.csv) to ASP.NET MVC server. Users will upload file that will be of size more than 40 MB to the server via internet. I am not understanding how can I achieve this as internet speed will be very important in this case. I dont want to save the same file on server, want to process the file as it will receive on the server and final output after processing want to save in SQL Server.

    Any comment would be greatly appreciated.

Comments are closed.