Manual File Downloads In ASP.NET

The Problem

Well, everything seemed to work fine until I accidentally looked at the HTML source code of a downloaded transcript file. Take look at this URL, for example; open the link in the browser and view the HTML source code.

Do you see what's wrong?

...I'm waiting...

Now you've got it - there are two<HTML> blocks in the file! The first block is the one I've generated dynamically in the SendItemToBrowser implementation. The second one was presumably added by the ASP.NET page-processing infrastructure. Although this is not a fatal error (IE and Mozilla display just the first HTML block), it is still an error. Moreover, the same mechanism is used to download binary files (.DOC and .MP3), where the effect of additional data at the end of the file can be fatal.

So there it was - my quest for a solution began.

The first one that came to mind was to use the Response.End method to terminate the ASP.NET page processing after the dynamic content was generated:

Private Sub Page_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Try
    ...
    ' Parse the query string - "Ref" and "Type" variables are mandatory.
    Dim TypeName, Ref As String
    Me.ParseQueryString(TypeName, Ref)
    ' Create a IDownloadService dynamically and delegate to it.
    Dim Service As IDownloadService = CreateDownloadService(TypeName)
    Service.SendItemToBrowser(Ref, Response)
    Response.End()
Catch ex As Exception
    SetError(ex.ToString())
    Trace.Warn(ex.ToString())
    Diagnostics.Trace.WriteLine(ex.ToString())
End Try
End Sub

The problem with this approach is that the Response.End call generates a ThreadAbortException. This exception is a very lusty beast. Even if you catch it, it is still rethrown at the end of the Catch block (or Finally block if there is any). The only way one can "swallow" the ThreadAbortException is by calling Thread.ResetAbort. But...that call will prevent the thread from being aborted, which is what we're trying to achieve in the first place.

In addition, good practice recommends that exceptions should not be thrown in the normal course of operation, and I wanted to stick with the rules.

You might also like...

Comments

About the author

Palo Mraz

Palo Mraz United States

I live in Slovakia with my wife, two sons (fulltime), one daughter (occasionally) and a dog. I've been doing Microsoft Windows development since 1988; primarily in VB. I'm a big fan of the MS .N...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Walking on water and developing software from a specification are easy if both are frozen.” - Edward V Berard