Friday, 19 March 2010

Downloading Large Files: Issues and Tricks

The ASP.NET framework includes the WriteFile and TransmitFile methods for serving up large chunks of data. As Dino explains, they're an improvement over plain old OutputStream, but you'll still need to address to the problems of tracking and resuming large file downloads on your own.

To serve users a server file, you don't need rocket science. A relatively simple piece of code would do the job. You use the OutputStream property of the HttpResponse object to write the bytes you want to send to the client. The following code snippet shows how to save an in-memory graphic document.

Bitmap bmp = new Bitmap(...); context.Response.ContentType = "image/jpeg"; bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);

Using the OutputStream object directly may be annoying at times. For this reason, the HttpResponse object features a few helper methods. One of these methods is BinaryWrite. As you can see, its implementation is quite straightforward:

public void BinaryWrite(byte[] buffer) { this.OutputStream.Write(buffer, 0, buffer.Length); }

The method accepts an array of bytes and just writes it out to the stream. What if you want to download an entire file? In theory, you must open the file, read its contents in separate blocks of data and write each block out to the stream. The ASP.NET framework, though, provides us with two specific methods for writing potentially large chunks of data down to the output stream. They are WriteFile and TransmitFile.

The WriteFile method does exactly what you should do yourself to send a file down to the client. It uses an internal file stream to access the content, reads the content in a single shot, and then writes it out to the output stream. In addition, the WriteFile method exposes a simple programming interface where all that you have to do is indicating the name of the file to download. To be precise, WriteFile has a number of overloads and may accept additional parameters, but this doesn't change the basic fact: the method writes out a server file.

Both WriteFile and BinaryWrite methods seem perfect for streaming data down to the client. However, both can put the Web server memory under pressure if called to work on very large files. Why? It's because both methods load the entire data block (the contents of the file or the byte array) into the Web server's memory. For large files, this can cause severe problems that can culminate in the recycling of the ASP.NET process. The TransmitFile method is designed to elegantly work around the problem. It sends output directly from a file to the ASP.NET ISAPI extension and then down to the client, without passing a humongous string to the ISAPI extension.

The TransmitFile method was introduced years ago through a hot-fix package for ASP.NET 1.x as documented in Microsoft KnowledgeBase article KB823409 and later incorporated in the .NET Framework 1.x SP1 and newer versions of ASP.NET. In summary, TransmitFile is the most stable and reliable of the other methods, although you won't notice any significant difference for most files.

Although TransmitFile makes large file downloads more stable than ever and defeats the problem of recycling, it is far from being a full solution to the problem of tracking and resuming large file downloads. For example, if a download fails, for whatever reason, TransmitFile can only start it again from the beginning. In the end, the perfect solution is creating your own file downloader that transmits the file piecemeal, thus avoiding unwanted pressure on the memory and giving the developer the chance of recovering from errors and latency.

Source : http://www.drdobbs.com/windows/202804466

No comments:

Post a Comment