Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / XAML

Downloading in Chunks using WCF and Silverlight

Rate me:
Please Sign up or sign in to vote.
4.81/5 (13 votes)
7 Sep 2010CPOL3 min read 77.5K   3K   48   21
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.

C#
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.

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

The following function is the download completed:

C#
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:

XML
<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:

C#
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:

C#
[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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Piyush has valuable experience in requirements gathering, designing, implementing, and maintaining data-driven, object-oriented and service based enterprise systems. In addition to his technical expertise, Piyush also published paper on knowledge management and he has excellent communication skills to cooperate with the clients.

He holds a Masters Degree in Computer Science from the University Of Michigan, USA

Comments and Discussions

 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey26-Feb-12 20:03
professionalManoj Kumar Choubey26-Feb-12 20:03 
GeneralRe: My vote of 5 Pin
Piyush Patell16-Apr-12 1:10
Piyush Patell16-Apr-12 1:10 
GeneralOutOfMemory Exception on FileSize 1 GB and Large Pin
om solanki20-Apr-11 2:51
om solanki20-Apr-11 2:51 
GeneralRe: OutOfMemory Exception on FileSize 1 GB and Large Pin
Piyush Patell16-Apr-12 1:08
Piyush Patell16-Apr-12 1:08 
GeneralHere is the VB.Net SLN Link : Pin
itayzoro16-Feb-11 3:59
itayzoro16-Feb-11 3:59 
GeneralRe: Here is the VB.Net SLN Link : Pin
Piyush Patell16-Apr-12 1:09
Piyush Patell16-Apr-12 1:09 
GeneralMy vote of 5 Pin
Thanlyin711-Jan-11 23:04
Thanlyin711-Jan-11 23:04 
GeneralRe: My vote of 5 Pin
Piyush Patell16-Apr-12 1:09
Piyush Patell16-Apr-12 1:09 
GeneralMy vote of 5 Pin
ashutosh k. shukla13-Sep-10 15:32
ashutosh k. shukla13-Sep-10 15:32 
GeneralRe: My vote of 5 Pin
Piyush Patell13-Sep-10 20:46
Piyush Patell13-Sep-10 20:46 
GeneralMy vote of 5 Pin
maq_rohit8-Sep-10 6:43
professionalmaq_rohit8-Sep-10 6:43 
GeneralRe: My vote of 5 Pin
Piyush Patell13-Sep-10 20:46
Piyush Patell13-Sep-10 20:46 
GeneralMy vote of 5 Pin
Kunal Chowdhury «IN»7-Sep-10 8:11
professionalKunal Chowdhury «IN»7-Sep-10 8:11 
GeneralRe: My vote of 5 Pin
Piyush Patell13-Sep-10 20:45
Piyush Patell13-Sep-10 20:45 
GeneralFix formatting Pin
Not Active18-Aug-10 2:02
mentorNot Active18-Aug-10 2:02 
GeneralRe: Fix formatting Pin
Piyush Patell4-Sep-10 22:00
Piyush Patell4-Sep-10 22:00 
GeneralRe: Fix formatting Pin
Not Active5-Sep-10 2:48
mentorNot Active5-Sep-10 2:48 
GeneralGood Work.. Pin
Md. Marufuzzaman18-Aug-10 1:49
professionalMd. Marufuzzaman18-Aug-10 1:49 
GeneralRe: Good Work.. Pin
Piyush Patell26-Aug-10 2:11
Piyush Patell26-Aug-10 2:11 
GeneralRe: Good Work.. Pin
Md. Marufuzzaman26-Aug-10 8:20
professionalMd. Marufuzzaman26-Aug-10 8:20 
GeneralRe: Good Work.. Pin
Piyush Patell26-Aug-10 20:49
Piyush Patell26-Aug-10 20:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.