Table of Contents
The Scenario
I was working recently in an intranet application that had a download page. The output HTML was similar to the following:
<li><a class="download"
href="\\MYSERVER\reports 2011\report1.zip" title="Report 1">Report 1</a></li>
<li><a class="download"
href="\\MYSERVER\reports 2011\report2.zip" title="Report 2">Report 2</a></li>
<li><a class="download"
href="\\MYSERVER\reports 2011\report 3.zip" title="Report 3">Report 3</a></li>
<li><a class="download"
href="\\MYSERVER\reports 2011\report 4.zip" title="Report 4">Report 4</a></li>
<li><a class="download"
href="\\MYSERVER\reports 2011\report 5&6.zip" title="Report 5&6">Report 5&6</a></li>
This was working fine in IE9, but not in other browsers. There was no action using Google Chrome, and using Firefox there was an error (HTTP Error 400 – Bad Request).
I tried to convert the file path to a file URI but it didn’t fix it. It continued to work on Internet Explorer only.
<li><a class="download"
href="file://MYSERVER/reports 2011/report1.zip" title="Report 1">Report 1</a></li>
<li><a class="download"
href="file://MYSERVER/reports 2011/report2.zip" title="Report 2">Report 2</a></li>
<li><a class="download"
href="file://MYSERVER/reports 2011/report 3.zip" title="Report 3">Report 3</a></li>
<li><a class="download"
href="file://MYSERVER/reports 2011/report 4.zip" title="Report 4">Report 4</a></li>
<li><a class="download"
href="file://MYSERVER/reports 2011/report 5&6.zip" title="Report 5&6">Report 5&6</a></li>
The solution was to create a custom ASP.NET download page. I also used jquery on the client side.
Step 1: Using jquery on the Client Side
The first step was to add an event handler to the download links. The request URI is encoded and is sent as a parameter to the download page. Creating an hidden iframe and setting the src attribute with the download link allows the file to be downloaded asynchronously.
$("a.download").bind("click", function (e) {
e.preventDefault();
var requestedFile = encodeURIComponent($(this).attr('href'));
var iframe = document.createElement("iframe");
iframe.src = 'Download.aspx?file=' + requestedFile;
iframe.style.display = "none";
document.body.appendChild(iframe);
});
Make sure you use encodeURIComponent
function to encode special characters in the filename.
Step 2: Create an ASP.NET Download Page
This is the source code of the download page:
protected void Page_Load(object sender, EventArgs e)
{
try
{
string requestFile = Request.QueryString["file"];
if(string.IsNullOrEmpty(requestFile))
{
throw new FileNotFoundException("File to download cannot be null or empty");
}
var uri = new Uri(requestFile);
string filename = Path.GetFullPath(uri.LocalPath);
var fileInfo = new FileInfo(filename);
if(!fileInfo.Exists)
{
throw new FileNotFoundException("File to download was not found", filename);
}
Response.ContentType = GetContentType(fileInfo.Extension);
Response.AddHeader("Content-Disposition",
"attachment; filename=\"" + fileInfo.Name + "\"");
Response.WriteFile(fileInfo.FullName);
Response.End();
}
catch(ThreadAbortException)
{
}
catch(FileNotFoundException ex)
{
Response.StatusCode = (int) System.Net.HttpStatusCode.NotFound;
Response.StatusDescription = ex.Message;
}
catch(Exception ex)
{
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
Response.StatusDescription =
string.Format("Error downloading file: {0}", ex.Message);
}
}
Some notes:
This is necessary in order to make the download work with a UNC share (\\MYSERVER\….) or a file URI (file://….)
var uri = new Uri(requestFile);
string filename = Path.GetFullPath(uri.LocalPath);
To avoid filename truncating, it’s necessary to wrap the filename with quotes:
Response.AddHeader("Content-Disposition",
"attachment; filename=\"" + fileInfo.Name + "\"");
References