Part 3-Suggestions on implementing large file upload in asp.net


This is continuation of blog posts part 1 and part 2

this post covers possible alternatives on implementing large file upload in asp.net

using fileupload control

  • SaveAs- internal implementation is explained part 2
  • property FileContent or PostedFile.InputStream. This again is using the HttpRawUploadedContent +temp file approach,but you can you get the content as a stream object,which you can use to save to a DB or any other location.

    Note: never use the property FileBytes,which loads all the file contents to memory.

  • HttpWorkerRequest and HttpMultipartContentTemplateParser

One of  is the most powerful class in asp.net is HttpWorkerRequeust .Because this where the whole asp.net framework implementation starts.For a long time i thought the asp.net framework most powerful things are HttpModules and handlers but i was wrong 🙂

From IIS,if you want anything to do in the managed asp.netframework,it starts with an instance of HttpWorkerRequest 

so for file upload we will have to rely on few methods of HttpWorkerRequest like GetTotalEntityBodyLength(), GetPreloadedEntityBody() and ReadEntityBody().

Lets use the httpworker request class 

a basic implementation looks like this

HttpContext downloadContext = HttpContext.Current;

FileStream fStream = null;
// Check if body contains data
if (_workerRequest.HasEntityBody())
{

// get the total body length
int requestLength = _workerRequest.GetTotalEntityBodyLength();
// Get the initial bytes loaded

//wr.GetPreloadedEntityBody() ?? wr.GetPreloadedEntityBody().Length;

byte[] _data=new byte[requestLength];

if (!_workerRequest.IsEntireEntityBodyIsPreloaded())
{
byte[] buffer = new byte[512000];
string[] fileName = downloadContext.Request.QueryString["fileName"].Split(new char[] { '\\' });
DirectoryInfo dir = Directory.CreateDirectory(downloadContext.Server.MapPath("~/Uploads") + "/" + Guid.NewGuid().ToString());
fStream = new FileStream(Path.Combine(dir.FullName, fileName[fileName.Length - 1]), FileMode.CreateNew);
// Set the received bytes to initial bytes before start reading
int receivedBytes, bytesToRead;
receivedBytes = _workerRequest.GetPreloadedEntityBodyLength();
if (receivedBytes > 0)
{
fStream.Write(_workerRequest.GetPreloadedEntityBody(), 0, receivedBytes);
}

while (requestLength > receivedBytes)
{
bytesToRead = requestLength - receivedBytes;
int bytesRead;
if (bytesToRead <= buffer.Length)
{
bytesRead = _workerRequest.ReadEntityBody(buffer, bytesToRead);
}
else
{
bytesRead = _workerRequest.ReadEntityBody(buffer, buffer.Length);
}

// Write the chunks to the physical file
fStream.Write(buffer, 0, bytesRead);
// Update the received bytes
receivedBytes += bytesRead;
}

fStream.Seek(0, SeekOrigin.Begin);
fStream.Read(_data, 0, requestLength);

//initialBytes = workerRequest.ReadEntityBody(buffer, requestLength - receivedBytes);
fStream.Flush();
fStream.Close();
return _data;
}
}

Now Lets have a revision of HTTP upload process.We have to have a  <INPUT type="file"> and/or ENCTYPE="multipart/form-data"  specified in the form tag.

http://en.wikipedia.org/wiki/File_select 
http://www.faqs.org/rfcs/rfc1867.html 

When the content gets to server,it will look like this( i tried uploading an image to and this is what got uploaded to site in question.Seeing the http traffic using fiddler  http://www.fiddler2.com/fiddler2/ )

POST http://<hostname>/convert/pic2html.cgi HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://<hostname>/convert/
Accept-Language: en-IN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Content-Type: multipart/form-data; boundary=---------------------------7dc10b1420476
Accept-Encoding: gzip, deflate
Host: www.text-image.com
Content-Length: 11182
Connection: Keep-Alive
Pragma: no-cache

-----------------------------7dc10b1420476
Content-Disposition: form-data; name="image"; filename="actionmethods.png"
Content-Type: image/x-png

�PNG
<<Content Goes here...Trimmed for brevity>>
<if you have other form input fields,we will see those as well>>

Content-Disposition: form-data; name="characters"

01
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="textType"

random
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="fontsize"

-3
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="width"

130
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="grayscale"

0
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="bgcolor"

BLACK
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="contrast"

0
-----------------------------7dc10b1420476
Content-Disposition: form-data; name="browser"

firefox
-----------------------------7dc10b1420476--

Why this is important ? Because if you are going to implement your own upload ,you will have to implement a parser which can parse this multi-part form data .By default asp.net does this for you (implemented with the help of following classes).

HttpMultipartContentTemplateParser
HttpRawUploadedContent
MultipartContentElement

If you would like to see a sample implementation,please check https://bitbucket.org/lorenzopolidori/http-form-parser/src 

You may find many more custom implementation in codeplex. So if you would like to implement a custom upload,you have to implement a multi part parser which can read the file in chunked form(from multi part data) and then process it .I would like to add a sample implementation later to this post but it is not yet ready.This is the roadmap of things i would like to implement

Comments (0)

Skip to main content