How Do I? File uploading in chunks using HttpHandler and HttpWebRequest
This is a sample code that shows how to upload file using HttpHandler in chunks. This may not seems like a very good idea in isolation but this could help when creating a file upload control in Silverlight. I already have an article that shows how to upload file using web service in chunk. You can read this article here. When talk about file uploading using web service, it has many disadvantages like 1- it has a limit of sending and receiving data and 2- it pads data that increase the sending data, to name a few problems.
HttpHandlers are better in many ways; this technique could be used to enable huge files. It will understand the entire authentication and authorization constrains already implemented in your web application.
This article has two distinct parts
1- How to send data in chunks using HttpWebRequest
2- How to receive and save data in HttpHandler
1- Open a file
2- Start reading a chunk
3- Convert the chunk in Base64 String
4- Send the chunk to HttpHandler along with some basic file information e.g. file name
HttpWebRequest will post data to HttpHandler because of data limitation and sercurity of data in a Key-Value pair.
And here is the code
private void ConvertToChunks()
{
//Open file
string file = MapPath("~/temp/1.xps");
FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
//Chunk size that will be sent to Server
int chunkSize = 1024;
// Unique file name
string fileName = Guid.NewGuid() + Path.GetExtension(file);
int totalChunks = (int)Math.Ceiling((double)fileStream.Length / chunkSize);
// Loop through the whole stream and send it chunk by chunk;
for (int i = 0; i < totalChunks; i++)
{
int startIndex = i * chunkSize;
int endIndex = (int)(startIndex + chunkSize > fileStream.Length ? fileStream.Length : startIndex + chunkSize);
int length = endIndex - startIndex;
byte[] bytes = new byte[length];
fileStream.Read(bytes, 0, bytes.Length);
ChunkRequest(fileName, bytes);
}
}
private void ChunkRequest(string fileName,byte[] buffer)
{
//Request url, Method=post Length and data.
string requestURL = "http://localhost:63654/hello.ashx";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// Chunk(buffer) is converted to Base64 string that will be convert to Bytes on the handler.
string requestParameters = @"fileName=" + fileName +
"&data=" + HttpUtility.UrlEncode( Convert.ToBase64String(buffer) );
// finally whole request will be converted to bytes that will be transferred to HttpHandler
byte[] byteData = Encoding.UTF8.GetBytes(requestParameters);
request.ContentLength = byteData.Length;
Stream writer = request.GetRequestStream();
writer.Write(byteData, 0, byteData.Length);
writer.Close();
// here we will receive the response from HttpHandler
StreamReader stIn = new StreamReader(request.GetResponse().GetResponseStream());
string strResponse = stIn.ReadToEnd();
stIn.Close();
}
1- Receive the chunk and file information
2- Convert back the chunk to byte[] from Base64 string
3- Save the chunk by
a. Creating a new file if file not existed
b. Opening the existing file
Here is the Code
public void ProcessRequest(HttpContext context)
{
//write your handler implementation here.
string fileName = context.Request.Params["fileName"].ToString();
byte[] buffer = Convert.FromBase64String ( context.Request.Form["data"]);
SaveFile(fileName, buffer);
}
public void SaveFile(string fileName, byte[] buffer)
{
string Path = HttpContext.Current.Server.MapPath("~/upload") +"\\"+ fileName;
FileStream writer = new FileStream(Path,File.Exists(Path)?FileMode.Append:FileMode.Create, FileAccess.Write);
writer.Write(buffer, 0, buffer.Length);
writer.Close();
}
To use HttpHandler, it must be configured in web.conf like shown below
<add verb="*" path="*.ashx" type="handlertest.IISHandler1, handlertest"/>
Hope this will help , Please click here to download the sample application. Please see the Default.aspx.cs for HttpWebRequest section and IISHandler1.cs for HttpHandler section.