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)
{
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 (Offset > FileSize)
{
return null;
}
byte[] TmpBuffer;
int BytesRead;
try
{
using (FileStream fs = new FileStream(FilePath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
fs.Seek(Offset, SeekOrigin.Begin);
TmpBuffer = new byte[BufferSize];
BytesRead = fs.Read(TmpBuffer, 0, BufferSize);
}
if (BytesRead != BufferSize)
{
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.