Sending Binary Files Over WCF

This is an interesting one – it is possible to load a binary file (such as an exe) in a .NET service and return it to the client via WCF. It’s actually not that complex either; in this example, I’ve created a basic service and console application.

Code

The code for the service is really straight forward:

    public class Service1 : IService1
    {
        public Stream GetData(int value)
        {
            FileStream stream = File.OpenRead(@"c:\tmp\MyFile");
            return stream;
        }
    }

And here is the Interface:

    [ServiceContract]
    public interface IService1
    {

        [OperationContract]
        Stream GetData(int value);
    }

The important part about the above code is that the method must return a Stream, and can only accept a single parameter (you can send large data by reversing this).

The client code is a little more involved. The Main() function of the console app is here:

        static void Main(string[] args)
        {
            Task rd = ReceiveData();
            rd.Wait();

And ReceiveData() looks like this:

        private static async Task ReceiveData()
        {
            ServiceReference1.Service1Client sc = new ServiceReference1.Service1Client();
            Stream stream = await sc.GetDataAsync();            

            using (var fs = File.Create(@"c:\tmp2\newfile.exe"))
            {
                int b;
                do
                {
                    b = stream.ReadByte();
                    fs.WriteByte((byte)b); 
                } while (b != -1);
            }
        }

As you can see, although the code is a bit messy, it’s not complex, and the bulk of the code is actually turning the Stream into a file (I’m sure there’s an easier way of doing this).

Configuration

The config files are the key here. The encoding and transfer mode need to be changed.

The service web.config:

    <bindings>
      <basicHttpBinding>
        <binding name="BasicStreaming" messageEncoding="Mtom" transferMode="Streamed"
                 closeTimeout="10:00:00"
                 />

      </basicHttpBinding>
    </bindings>

Create an endpoint for the service and bind it to above:

  <system.serviceModel>
    <services>
      <service name="FileService.Service1">
        <endpoint address="Service1.svc" binding="basicHttpBinding"
          bindingConfiguration="BasicStreaming" contract="FileService.IService1" />
      </service>
    </services>

So, the transfer mode is streamed, and the encoding is ‘Mtom’. Make sure that the endpoint is configured against the binding (otherwise it’ll use the default binding, repeatedly moan that it’s out of memory and mismatched for no apparent reason and you’ll spend ages wondering why).

The client config can be updated using the “Update Service Reference” option; however, double check what it adds.

The App.config changes from the client:

    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicStreaming" closeTimeout="10:00:00" 
                    maxReceivedMessageSize="400000000" messageEncoding="Mtom" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:17065/Service1.svc/Service1.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicStreaming"
                contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
        </client>
    </system.serviceModel>

The only real thing of note in the client is the `maxReceivedMessageSize`; this has to be big enough to take your largest file. Obviously, the timeout settings matter, but maybe if you’re taking 10 minutes to transfer then you’ve got bigger problems.

The End

That’s it – it all works neatly, and looks deceptively easy!

3 thoughts on “Sending Binary Files Over WCF

  1. Mike

    This line here is causing a major problem:

    Stream stream = await sc.GetDataAsync();

    Severity Code Description Project File Line Suppression State
    Error CS7036 There is no argument given that corresponds to the required formal parameter ‘value’ of ‘Service1Client.GetDataAsync(int)’ GothamIO_Client C:\Users\Bagshot\source\repos\GothamIO_Lib\GothamIO_Client\Program.cs 32 Active

    Seriously, I’m tearing my hair out. Do you know why I get this error and you don’t?

    Reply
  2. pcmichaels Post author

    Without seeing your code it would be difficult to advise – if you post what you have then I’m happy to help. It has been a while since I wrote this article, so something in WCF may have moved on. If I get chance in the near future, I’ll revisit it and try again. If you do come across a solution then I’d love to add that to the article for any future visitors.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *