Complete code is available at Developer Code Samples

It is common scenario to have the need to upload/download large files to/from server. There are mainly two options to upload/download large files in WCF applications

  1. WCF Streaming
  2. WCF Chunking

In this blog post we will discuss how to implement WCF Streaming and WCF Chunking. We will use WCF Chunking to upload a large file and download it using WCF Streaming.

Here is the WCF Service Contract

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string FileUpload(FileData fileData);
    [OperationContract]
    bool FileUploadDone(string filename);
    [OperationContract]
    Stream DownloadFile();
}

We will use FileUpload() function to upload the file. (Note: the return value is string as I don’t like throwing exceptions, I always like to return Boolean or string with error message). To download the file we will use DownloadFile() function.

FileUpload() takes a WCF Data Contract as parameter, lets review its data structure :

[DataContract]
public class FileData
{
    [DataMember]
    public string Filename { get; set; }
    [DataMember]
    public int Offset { get; set; }
    [DataMember]
    public byte[] Buffer { get; set; }
}
  
 

The most important member in this data structure is Buffer which holds the file buffer and Offset is used to determine the current buffer’s offset from the beginning of the file.

Lets look at the implementation of the FileUpdate() function

private static Dictionary<string, FileStream> wcfFileStreams 
= new Dictionary<string, FileStream>();
  
public string FileUpload(FileData fileData)
{
    FileStream fs;
    string filepath = "c:\\temp\\" + fileData.Filename;
    try
    {   
        lock (wcfFileStreams)
        {
            wcfFileStreams.TryGetValue(filepath, out fs);
            if (fs == null)
            {
                fs = File.Open(filepath, FileMode.Create, FileAccess.ReadWrite);
                wcfFileStreams.Add(filepath, fs);
            }
        }
        fs.Write(fileData.Buffer, 0, fileData.Buffer.Length);
        fs.Flush();
        return string.Empty;
    }
    catch (System.Exception ex)
    {
        FileUploadDone(filepath);
        return ex.ToString();
    }
   
    
}
  

Here we are going to save the uploaded file to c:\temp folder.

Note: we have Dictionary  object to store our FileStream, if multiple clients upload different files at the same time, we know which FileStream to update. We will close the FileStream object when the client invokes WCF Operation - FileUploadDone()

Now, lets look at the client code

ServiceReference1.FileData fileData = new ServiceReference1.FileData();
 fileData.Filename = fileInfo.Name;
 fileData.Offset = offset;
 fileData.Buffer = new byte[BUFFER_SIZE];

 FileStream fs = fileInfo.OpenRead();
 newOffset = fs.Seek(offset, SeekOrigin.Begin);
 int read = fs.Read(fileData.Buffer, 0, BUFFER_SIZE);
 if (read != 0)
 {
     offset += read;
     c.FileUploadAsync(fileData);
 }
 else
 {
     c.FileUploadDoneAsync(fileInfo.Name);
 }
  

Client is going to read small chunks of the file and is going to upload them using the FileData – WCF Data Contract. When the file Read() returns zero bytes, the client is going to call FileUploadDone() to tell the server that all pieces of the file are uploaded.

Note : here I am using Async-pattern so that client’s calling thread doesn’t have to wait for response from the server.

 

WCF Streaming

Now lets look at WCF Streaming implementation. Streaming implementation is very easy, we just have to return the stream object to the WCF.

Note: here the sample code is returning the last uploaded file

public Stream DownloadFile()
{   
    if (!string.IsNullOrEmpty(_LastUploadedFilename))
    {
        return File.OpenRead(_LastUploadedFilename);
    }
    return null;
}
  

Lets review the client code.

The client code calls DownloadFile() and when the completed event is fired, it will call the EndDownloadFile() to get the file buffer

private void buttonDownloadFile_Click(object sender, RoutedEventArgs e)
{
    c.DownloadFileAsync();
}

void DownloadFileCallback(IAsyncResult asyncResult)
{
    SLWCFChunking.ServiceReference1.IService1 proxy = 
        (SLWCFChunking.ServiceReference1.IService1)asyncResult.AsyncState;
    byte[] buffer = proxy.EndDownloadFile(asyncResult);
}
  

We will learn more about WCF Streaming in the next post.

 

Complete code

Complete code is available at Developer Code Samples