WCF support two modes for transferring messages, Buffered and Streamed.
Buffered: In this case, it holds whole message in memory buffer until the transfer is complete and Message can not be read/ used, until the transfer completes.
Streamed: In streamed transfer, message get exposed as stream. The receiver starts processing the message before it is completely delivered. Using streamed transfer mode for large message size can increase the scalability and it removes the requirement of large memory buffers.

In this code snippet, we are going to see sample code for creating a WCF service, which supports file upload with streamed transfer mode; Will also include client application(console application), which is consuming the sample WCF service and streaming file.

Files description:
WCF Service Application
WCF Service - IFileUploadService.cs: It contains 2 classes and 1 interface:
   - IFileUploadService: Interface/ contract of the service.
   - UploadRequest: Message contract, will be sent as parameter to WCF service - UploadData function.
   - UploadResponse: Message contract, will be returned as response from WCF service - UploadData function.
WCF Service - FileUploadService.cs: Service class, which implements IFileUploadService interface. Contains WCF service function implementation.
WCF Service - Web.config changes: This part contains partial changes, required in configuration for WCF service to work under streamed mode.
Client Application
CustomStream.cs: This class is our custom stream class, which is getting inherited from System.IO.Stream class; And we are passing this stream to our WCF service UploadData function, instead of .Net built-in stream class. Well, we could have passed the .Net built-in stream class, but then our client app will not have any information on, how many bytes are getting read by WCF service. So, we created our custom stream class, which raises an event in our client application, when bytes read count changes in WCF service.
Program.cs: Contains Main function(entry point of the application) and calls the WCF service to upload a file from local machine to respective server.

Let's see code under each file below:

Service Implementation

WCF service sample IFileUploadService interface code

[ServiceContract]
public interface IFileUploadService
{
    [OperationContract]
    string GetData(int value);

    [OperationContract]
    UploadResponse UploadData(UploadRequest uploadRequest);
}

[MessageContract]
public class UploadRequest : IDisposable
{
    [MessageHeader(MustUnderstand = true)]
    public string FileName { get; set; }

    [MessageBodyMember(Order = 1)]
    public Stream Stream { get; set; }

    public void Dispose()
    {
        if (Stream == null)
        {
            return;
        }

        Stream.Close();
        Stream = null;
    }
}

[MessageContract]
public class UploadResponse
{
    [MessageBodyMember(Order = 1)]
    public bool UploadSucceeded { get; set; }
}


WCF service sample FileUploadService class, interface implementation code


[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
ConcurrencyMode = ConcurrencyMode.Single)]
public class FileUploadService : IFileUploadService
{
    public UploadResponse UploadData(UploadRequest request)
    {
        try
        {
            var uploadDirectory = @"C:\uploads";

            // Try to create the upload directory if it does not yet exist
            if (!Directory.Exists(uploadDirectory))
            {
                Directory.CreateDirectory(uploadDirectory);
            }

            // Check if a file with the same filename is already
            // present in the upload directory. If this is the case
            // then delete this file
            var path = Path.Combine(uploadDirectory, request.FileName);

            if (File.Exists(path))
            {
                File.Delete(path);
            }

            // Read the incoming stream and save it to file
            const int bufferSize = 4096;

            var buffer = new byte[bufferSize];
            using (var outputStream = new FileStream(path,
                FileMode.Create, FileAccess.Write))
            {
                var bytesRead = request.Stream.Read(buffer, 0, bufferSize);
                while (bytesRead > 0)
                {
                    outputStream.Write(buffer, 0, bytesRead);
                    bytesRead = request.Stream.Read(buffer, 0, bufferSize);
                }
                outputStream.Close();
            }
            request.Stream.Close();
            request.Stream.Dispose();

            return new UploadResponse
            {
                UploadSucceeded = true
            };
        }
        catch (Exception ex)
        {
// Note down exception some where!

            request.Stream.Close();
            request.Stream.Dispose();
            return new UploadResponse
            {
                UploadSucceeded = false
            };
        }
    }
}


WCF service sample config changes

<system.web>
    <httpRuntime maxRequestLength="2048000"/>
</system.web>
<system.servicemodel>
    <services>
        <service name="ProjectNamepace.FileUploadService"
behaviorconfiguration="FileUploadServiceBehavior">
        <endpoint binding="basicHttpBinding"
behaviorconfiguration="FileUploadEndPointBehavior"
                  bindingconfiguration="FileUploadServiceBinding"
contract="ProjectNamepace.IFileUploadService">
</endpoint>
        </service>
    </services>
    <bindings>
        <basichttpbinding>
            <binding name="FileUploadServiceBinding"
transfermode="Streamed" messageencoding="Mtom"
                     maxreceivedmessagesize="2147483648"
closetimeout="00:01:00" opentimeout="00:01:00"
                     receivetimeout="00:15:00" sendtimeout="00:15:00">
                <security mode="None">
                    <transport clientcredentialtype="None"></transport>
                </security>
            </binding>
        </basichttpbinding>
    </bindings>
    <behaviors>
        <endpointbehaviors>
            <behavior name="FileUploadEndPointBehavior">
                <dispatchersynchronization asynchronoussendenabled="true">
</dispatchersynchronization>
            </behavior>
        </endpointbehaviors>
    </behaviors>
</system.servicemodel>


Client Implementation

WCF service sample CustomStream class code

public class CustomStream : Stream
{
    private readonly FileStream _file;
    private readonly long _length;
    private long _bytesRead;

    public class ProgressChangedEventArgs : EventArgs
    {
        public long BytesRead;
        public long Length;

        public ProgressChangedEventArgs(long bytesRead, long length)
        {
            BytesRead = bytesRead;
            Length = length;
        }
    }
    
    public event EventHandler<ProgressChangedEventArgs> ProgressChanged;

    public CustomStream(FileStream fileStream)
    {
        _file = fileStream;
        _length = _file.Length;
        _bytesRead = 0;
        if (ProgressChanged != null)
        {
            ProgressChanged(this,
new ProgressChangedEventArgs(_bytesRead, _length));
        }
    }

    public double GetProgress()
    {
        return ((double)_bytesRead) / _file.Length;
    }

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void Flush() { }

    public override long Length
    {
        get
        {
            return _length;
        }
    }

    public override long Position
    {
        get { return _bytesRead; }
        set
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        int result = _file.Read(buffer, offset, count);
        _bytesRead += result;
        if (ProgressChanged != null)
        {
            ProgressChanged(this, new ProgressChangedEventArgs(_bytesRead, _length));
        }
        return result;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public override void SetLength(long value)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}


WCF service sample console application Program class code

internal class Program
{
    private static void Main(string[] args)
    {
        try
        {
            new Program().UploadFile().Wait();
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
            return;
        }
        catch (AggregateException ex)
        {
            foreach (var e in ex.InnerExceptions)
            {
                Console.WriteLine("ERROR: " + e.Message);
            }
        }
    }
        
    private async Task UploadFile()
    {
        var serviceClient = new FileUploadServiceClient();

        try
        {
            var fileNameToUpload = @"C:\UploadFrom\Test.jpg";

            // File should exist first!
            if (File.Exists(fileNameToUpload))
            {
                using (var stream = File.OpenRead(fileNameToUpload))
                {
                    using (var progressStream = new StreamWithProgress(stream))
                    {
                        progressStream.ProgressChanged +=
UploadStreamWithProgress_ProgressChanged;
                        Console.WriteLine(DateTime.Now + ": Filename: "
+ fileNameToUpload
+ "Upload starting, file size: "
+ progressStream.Length + " Bytes!");
                        progressStream.Position = 0;
                        var result = await serviceClient.UploadDataAsync(fileNameToUpload,
progressStream);
                        if (result.UploadSucceeded)
                        {
                            Console.WriteLine(DateTime.Now + ": Upload completed!");
                        }
                        else
                        {
                            Console.WriteLine(DateTime.Now + ": Upload failed!");
                        }
                    }
                }
            }
            else
            {
                Console.WriteLine("Provided file name does not exist.");
            }
        }
        catch (Exception ex)
        {
            serviceClient.Abort();
            serviceClient.Close();
            Console.WriteLine("Error occurred:" + ex.Message);
        }
        finally
        {
            serviceClient.Abort();
            serviceClient.Close();
        }
    }

    private static void UploadStreamWithProgress_ProgressChanged(
object sender, StreamWithProgress.ProgressChangedEventArgs e)
    {
        if (e.Length != 0)
        {
            Console.WriteLine(DateTime.Now + ": Streamed "
+ e.BytesRead + " Bytes.");
        }
    }
}


WCF service sample console application app config changes

<system.serviceModel>
  <bindings>
    <basicHttpBinding>
      <binding name="BasicHttpBinding_IFileUploadService" closeTimeout="00:01:00"
        openTimeout="00:01:00" receiveTimeout="00:15:00" sendTimeout="00:15:00"
        maxReceivedMessageSize="2147483648" messageEncoding="Mtom" transferMode="Streamed"/>
    </basicHttpBinding>
  </bindings>
</system.serviceModel>


References:

MSDN: Streaming message transfer
MSDN: How to enable streaming

Discussion
42 / 7 =
** To prevent abusing comments from publishing, posted comments will be reviewed and then published!
 Mritunjay Kumar
Works at Mindfire Solutions

I mostly work with C#, ASP.NET, MVC, WCF, Web API, Entity FrameWork, MS Sql.