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
My name is Rui Jarimba and I was born in Madeira island, Portugal and I currently live in Rome, Italy.
I have more than 10 years of experience developing software using the .NET Framework and other technologies (Web development, Databases, ...).
Some of my professional interests are: software development best practices, software architecture, cloud computing, Continuous Integration (CI), Continuous Delivery (CD) and agile methodologies such as Scrum, Kanban, Lean and any other methodology that can help me to become a better and more productive software engineer.
I believe in good code - code that is readable, maintainable, reusable, testable and deployable. This means that I'm not the "quick and dirty" type, I write code for the medium/long term whenever possible.
Something else about me - I love music, I am an amateur photographer, not a big fan of gyms (I prefer to do some outdoor activity such as walking/hiking), big foodie (I love Mediterranean cuisine and my glass of wine!).