Visual Studio: Unable to start debugging on the web server

This happened to me today – I was getting the same error whenever I tried to debug an ASP.NET application using Visual Studio:

Unable to start debugging on the web server. Could not start ASP.NET debugging. More information may be available by starting the project without debugging.

debug1

My initial reaction was to check if there was something wrong in IIS, and I was right: the application pool used by the application I wanted to debug was stopped!

debug2

At that moment I realised that I changed my Windows password 2 or 3 hours before trying to debug the application. Given that the application pool was running under my credentials, all I had to do to fix the issue was to right-click the application pool and go to Advanced Settings > Identity and update my password 🙂

 

ASP.NET: Downloading files from a UNC share

Implementing a cross-browser solution for downloading files from a UNC share in ASP.NET applications

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 IE 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 used also 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); // triggers download page
});

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");
        }

        // Get file name from URI string in C#
        // http://stackoverflow.com/a/1105614
        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);
        }


        // get content type based on file extension. Example:
		// http://stackoverflow.com/a/691599
        Response.ContentType = GetContentType(fileInfo.Extension);

        Response.AddHeader("Content-Disposition", 
                           "attachment; filename=\"" + fileInfo.Name + "\"");
        Response.WriteFile(fileInfo.FullName);
        Response.End();
    }
    catch(ThreadAbortException)
    {
        // ignore exception
    }
    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

Technorati Tags: , , ,