2005-10-25
| Table of Contents: |
| Rate This Article: | Add This Article To: |
( Page 3 of 3 )
The Answer, Part 2
But implementing resumable downloads required another piece of the puzzle. This comes from our old friend HTML.
I was quite surprised that the HTML specification supports headers designed specifically for implementing resumable downloads. These headers use the concept of ranges to permit a download to resume where it left off.
Two header tags are critical:
- The Accept-Ranges element tells the client that it supports resuming downloads.
- The ETag (entity tag) element provides a unique ID identifying the session.
For example, the headers returned by IIS to a client at the start of a resumable download might look like this:
HTTP/1.1 200 OK Connection: close Date: Wed, 7 Sep 2005 21:10:19 GMT Accept-Ranges: bytes Last-Modified: Sun, 4 Sep 2005 05:34:51 GMT ETag: "21accd5ffa11d90:3099" Cache-Control: private Content-Type: application/x-zip-compressed Content-Length: 6511789
Having received these headers, Internet Explorer knows that the server supports resuming downloads. Then, if the download is interrupted, IE sends the ETag value and a range value (which indicates how much has been downloaded so far) back to the server to try to resume the download. Here's an example of some of the headers that would be sent in this situation:
GET http://204.181.112.112/data.zip HTTP/1.0 Range: bytes=1254660- Unless-Modified-Since: Wed, 7 Sep 2005 21:10:19 GMT If-Range: "21accd5ffa11d90:3099"
You can see that these headers include the URL of the file that was being downloaded as well as the date and time the original download was commenced. The server uses this value to determine if the file has changed and, if so, begins a new download. If the file has not changed, IIS resumes the download with a response that includes headers such as these:
HTTP/1.1 206 Partial Content Content-Range: bytes 1254660-6511788/6511789 Accept-Ranges: bytes Last-Modified: Wed, 7 Sep 2005 21:10:19 GMT ETag: "21accd5ffa11d90:3099" Cache-Control: private Content-Type: application/x-zip-compressed Content-Length: 5257329
Note that the Content-Length value now specifies the remaining bytes to be downloaded. In other words, the total file size minus the Range value that IE sent to the server when the download was interrupted.
Implementing in Code
In order for your ASP.Net application to implement download resumability, it must intercept the requests from the client and respond accordingly based on the header content. This is done using the IHttpHandler interface that is provided as part of the Framework. Creating a class based on this interface lets you intercept and handle client requests without any reliance on IIS's automatic responses. Start by creating a new Class Library project and assigning an appropriate name, such as BinHandler for a class that will handle downloads of .BIN files. Then:
- Use the Project->Add Reference command to add a reference to the
System.Web.dllassembly. - Import the
System.Webnamespace. - Rename the class and add the Implements
IHttpHandlerstatement. - Implement the
IsReusableproperty, returningFalse. This prevents the handler from being pooled, necessary because it is a synchronous handler. - Implement the
ProcessRequestmethod, leaving it empty for now.
At this point your source code, will look something like this:
Imports System.Web
Public Class BinHandler
Implements IHttpHandler
Public ReadOnly Property IsReusable() As Boolean _<
Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
End Sub
End Class
As you may have guessed, it's the ProcessRequest method where the action takes place. When your handler is deployed (as described below), each request for the specified file type will result in this method being called. Your code then must read the HTTP headers that were sent in the client request and respond appropriately, for example starting a download from the beginning or resuming it at some intermediate position.
There are many ways that this functionality can be accomplished and I am not going to present a specific implementation. Rather, I will present some guidelines as to what I think is the best general approach.
Working with HTTP is greatly simplified by the HttpContext object that is passed to the ProcessRequest method. You use this object to access both an HttpRequest object for reading the headers that were received, and an HttpResponse object for defining the response to be sent back to the client. For example:
Public Sub ProcessRequest(ByVal objContext As System.Web.HttpContext) _
Implements System.Web.IHttpHandler.ProcessRequest
Dim oResponse As HttpResponse = objContext.Response
Dim oRequest As HttpRequest = objContext.Request
...
End Sub
Once you have read the headers you can create the response. For example, supporting only GET and HEAD requests requires that you send a "Not supported" response to the client if the request is for any other method:
If Not oRequest.HttpMethod.Equals(HTTP_METHOD_GET)
Or _
Not oRequest.HttpMethod.Equals(HTTP_METHOD_HEAD) Then
oResponse.StatusCode
= 501 ' Not implemented
...
Likewise, if the file that was requested for download cannot be found on the server, send the "Not found" response:
If Not FileFound Then
oResponse.StatusCode = 404
....
The remainder is mostly detail work, opening the file and streaming it in chunks to the client. If a request comes in to resume a download, the information in the header will tell you where you should seek to in the file before resuming the streaming.
Deployment
The next step is to deploy the project to your Web site:
- Create a new folder with the appropriate name (e.g., BinHandler) in C:\INetPub\Wwwroot.
- Create a Bin folder within this new folder.
- Copy the file BinHandler.dll (or whatever the name is) from your Visual Studio project folder to this new Bin folder.
Next, you must mark the new folder as a Web application:
- Start IIS and expand the folder tree to locate the new BinHandler folder.
- Right-click the folder name and select Properties from the popup menu.
- Click the Directory tab.
- Click Create.
Leave the dialog box open, because you'll need it for the next steps.
Mapping the Handler
To have requests for downloads routed to your handler, you must map the extensions of the files to be downloaded to the application. This too is done in IIS.
- Still in the Properties dialog box for your application, click the Configuration button.
- In the next dialog box, on the Mappings tab, click Add.
- Enter the following in the Executable text box where <WindowsDir> is the name of the Windows folder (usually just Windows) and <version #> is the .Net framework version number:
<a href="file:///C:/Windows/Microsoft.NET/Framework/%3Cversion"> C:\<WindowsDir>\Microsoft.NET\Framework\<version #>\Aspnet_isapi.dll
- Enter *.bin (or whatever file extension you are mapping) into the Extension text box.
- Make sure that the Check that File Exists option is cleared. In Windows Server 2003 this option is called Verify that File Exists.
- Click OK to close all dialog boxes.
Summing Up
Implementing resumable downloads takes a bit of effort. You have to decide whether it is worth it for your Web site. I believe that it merits consideration when you have a large number of site visitors who are downloading large files. The reduction is load on the server and the decrease of user frustration will probably be worth it.
![]() |
|


