Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Downloading in Chunks using WCF and Silverlight

0.00/5 (No votes)
7 Sep 2010 1  
Download the large file in chunk using WCF service and Silverlight

Acknowledgement

The project is about downloading the large file (GB) in chunks. You can download the large file in less time without getting any error. Most people use chunk in video streaming and for P2P Network. The chunk selection in P2P network is very crucial. Chunk was written to serve one purpose, and do it well: Split files into differently-sized chunks, primarily so that large files can be transported via media that is smaller than the size of the file.

Introduction

We need a functionality that can download the large file. Downloading large file in one shot is risky so the idea is from the UI (Silverlight application) user can call the WCF function to download the Chunk (let’s say 10 MB) per call. Once WCF returns the Chunk data, the Silverlight application will open the FileDialog and write the data into the stream, if the file size is greater than the chunk size, the program will call the WCF function again and get the next chunk.

This way, you can securely download the large file. Here we are going to use Silverlight and WCF technology.

Background

Let’s say you want to download the large file from your UI (which is running on client side) and the file resides at server side. You can call the WCF function and get the chunk of data and write this data into the FileStream. The WCF function will be recursive so that this function will get the Chunk of data till the entire file has been downloading.

Using the Code

The attached solution contains two projects, one is Silverlight and the other one is web project which contains the XAP file as well as Service class.

The following function is in Silverlight page which calls the WCF function to get the Chunk data:

Note: You have to entered valid fileSize (size of the document in Bytes) in the code.

public void DownloadFile(string DocURL)
        {
            // first you should get the file size from the server side in bytes.
            fileSize = 825344;
            service = new DownloadFileClient();
            isFirstCall = true;
            service.InnerChannel.OperationTimeout = new TimeSpan(0, 30, 0);
            docName = DocURL;
            service.DownloadChunkAsync(DocURL, I64Offset, i32ChunkSize);
            service.DownloadChunkCompleted += 
                new EventHandler<DownloadChunkCompletedEventArgs>(
                service_DownloadChunkCompleted);
        }

The following line will increase the WCF call time to 30 mins, in some cases what happens when your WCF function takes a longer time to perform some operation is it gets TomeOut. To prevent this, write the following code.

service.InnerChannel.OperationTimeout = new TimeSpan(0, 30, 0);

The following function is the download completed:

void service_DownloadChunkCompleted(object sender, DownloadChunkCompletedEventArgs e)
        {
            try
            {
                Byte[] byteArrayFile = (Byte[])e.Result;
                if (isFirstCall)
                {
                    MessageBox _oBox = MessageBox.Show("Download file in chunk",
                        "Are you sure to download the file ?", MsgBoxButtons.YesNo,
                        MsgBoxIcon.Error, OnDialogClosed);
                }
                isFirstCall = false;
                if (fileDialog != null)
                {
                    WriteIntoFile(fileDialog, byteArrayFile);
                    I64Offset = I64Offset + i32ChunkSize;
                    if (I64Offset < fileSize)
                    {
                        IsFileToAppend = true;
                        service.DownloadChunkAsync(docName, I64Offset, i32ChunkSize);
                    }
                    else
                    {
                        I64Offset = 0;
                        fileStream.Close();
                        System.Windows.MessageBox.Show("File downloaded successfully.");
                    }
                }
                else
                    service.DownloadChunkAsync(docName, I64Offset, i32ChunkSize);
            }
            catch (Exception ex)
            {
            }
        }

For the MessageBox, see the MessageBox.xaml file. In Silverlight, to open the fileDialog, you need to call it from USER initiated event. I created custom MessageBox class which is Model based.

WriteIntoFile function will write the data into the Stream. You can see in the above code that I am calling WCF function again and again till it satisfies the if (I64Offset < fileSize) condition.

Once the download is completed, I close the FileStream, and display successful message to the user.

WCF Settings

In the web.config, do the following settings:

<system.serviceModel>
	<behaviors>
		<serviceBehaviors>
			<behavior 
                           	name="DownloadFileInChunk.Web.Service.DownloadFileBehavior">
			<serviceMetadata httpGetEnabled="true"/>
			<serviceDebug includeExceptionDetailInFaults="false"/>
			</behavior>
		</serviceBehaviors>
	</behaviors>
	<bindings>
		<basicHttpBinding>
			<binding name="myServicesBinding" 
                               receiveTimeout="00:10:00" sendTimeout="00:10:00"
                               openTimeout="00:10:00" closeTimeout="00:10:00"
                               maxReceivedMessageSize="2147483647"
                               maxBufferSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="256" maxStringContentLength="2147483647"
    maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
			</binding>
		</basicHttpBinding>
	</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
	<services>
		<service
         behaviorConfiguration="DownloadFileInChunk.Web.Service.DownloadFileBehavior"
         name="DownloadFileInChunk.Web.Service.DownloadFile">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="myServicesBinding"
     contract="DownloadFileInChunk.Web.Service.IDownloadFile"/>
		</service>
	</services>
</system.serviceModel>

The WCF download in chunk function is shown below:

public byte[] DownloadChunk(String DocUrl, Int64 Offset, Int32 BufferSize)
        {
            String FilePath = HttpContext.Current.Server.MapPath(DocUrl);
            if (!System.IO.File.Exists(FilePath))
                return null;
            Int64 FileSize = new FileInfo(FilePath).Length;
            //// if the requested Offset is larger than the file, quit.
            if (Offset > FileSize)
            {
                return null;
            }
            // open the file to return the requested chunk as a byte[]
            byte[] TmpBuffer;
            int BytesRead;
            try
            {
                using (FileStream fs = new FileStream(FilePath, FileMode.Open,
                    FileAccess.Read, FileShare.Read))
                {
                    fs.Seek(Offset, SeekOrigin.Begin);
                    // this is relevant during a retry. otherwise, it just seeks to
                    // the start
                    TmpBuffer = new byte[BufferSize];
                    // read the first chunk in the buffer (which is re-used for
                    // every chunk)
                    BytesRead = fs.Read(TmpBuffer, 0, BufferSize);
                }
                if (BytesRead != BufferSize)
                {
                    // the last chunk will almost certainly not fill the buffer,
                    // so it must be trimmed before returning
                    byte[] TrimmedBuffer = new byte[BytesRead];
                    Array.Copy(TmpBuffer, TrimmedBuffer, BytesRead);
                    return TrimmedBuffer;
                }
                else
                    return TmpBuffer;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

The WCF interface:

[ServiceContract]
interface IDownloadFile
{
[OperationContract]
byte[] DownloadChunk(String Docurl, Int64 Offset, Int32 BufferSize);
}

Points of Interest

People who need to download large files can use this method. Downloading in chunks is much faster and reliable. We can use this method in video streaming where you have to get the data from the server and load video data into client side. Also the interesting point is to use downloading chunk in P2P network. The selection algorithm of chunk in P2P network is handy in this case. Data-driven P2P streaming systems can potentially provide good playback rate to a large number of viewers. One important design problem in such P2P systems is to determine the optimal chunk selection policy that provides high continuity playback under the server’s upload capacity constraint.

Also, we can use MTOM web service to get the Chunks from the server.

References

History

This is the first version of downloading in chunk using WCF in Silverlight project.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here