48

After a user clicks a button, I want a file to be downloaded. I've tried the following which seems to work, but not without throwing an exception (ThreadAbort) which is not acceptable.

    System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
    response.ClearContent();
    response.Clear();
    response.ContentType = "text/plain";
    response.AddHeader("Content-Disposition", "attachment; filename=" + fileName + ";");
    response.TransmitFile(Server.MapPath("FileDownload.csv"));
    response.Flush();
    response.End();  
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James Stevenson
  • 619
  • 2
  • 7
  • 9
  • 2
    You can check this similar question: http://stackoverflow.com/questions/2378204/context-response-end-and-thread-was-being-aborted – Omer Cansizoglu Aug 28 '13 at 00:18
  • 4
    `response.End()` is causing the `ThreadAbortException`. – Karl Anderson Aug 28 '13 at 01:08
  • 2
    This is a bug in the .NET framework and has been reported in numerous SO questions. Catch the ThreadAbort and be done. – debracey Aug 28 '13 at 02:03
  • 2
    possible duplicate of [How to implement a file download in asp.net](http://stackoverflow.com/questions/37650/how-to-implement-a-file-download-in-asp-net) – Mayank Pathak Aug 28 '13 at 03:52
  • 2
    The issue is that I need several files to be downloaded. When an exception is thrown, it interrupts the download of the of the following files, even if the exception is caught. – James Stevenson Aug 28 '13 at 15:41

7 Answers7

90

You can use an HTTP Handler (.ashx) to download a file, like this:

DownloadFile.ashx:

public class DownloadFile : IHttpHandler 
{
    public void ProcessRequest(HttpContext context)
    {   
        System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
        response.ClearContent();
        response.Clear();
        response.ContentType = "text/plain";
        response.AddHeader("Content-Disposition", 
                           "attachment; filename=" + fileName + ";");
        response.TransmitFile(Server.MapPath("FileDownload.csv"));
        response.Flush();    
        response.End();
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Then you can call the HTTP Handler from the button click event handler, like this:

Markup:

<asp:Button ID="btnDownload" runat="server" Text="Download File" 
            OnClick="btnDownload_Click"/>

Code-Behind:

protected void btnDownload_Click(object sender, EventArgs e)
{
    Response.Redirect("PathToHttpHandler/DownloadFile.ashx");
}

Passing a parameter to the HTTP Handler:

You can simply append a query string variable to the Response.Redirect(), like this:

Response.Redirect("PathToHttpHandler/DownloadFile.ashx?yourVariable=yourValue");

Then in the actual handler code you can use the Request object in the HttpContext to grab the query string variable value, like this:

System.Web.HttpRequest request = System.Web.HttpContext.Current.Request;
string yourVariableValue = request.QueryString["yourVariable"];

// Use the yourVariableValue here

Note - it is common to pass a filename as a query string parameter to suggest to the user what the file actually is, in which case they can override that name value with Save As...

Karl Anderson
  • 34,606
  • 12
  • 65
  • 80
  • 1
    Thanks for the reply. I want to pass folder location as parameter, so passing it in query won't be the good idea. Is there any other way, we can pass values? – Sagar Mahajan May 28 '14 at 05:41
  • 1
    @KarlAnderson is it possible to use this via $.ajax method? I have a single page application where I need to use this approaching of downloading file via asp.net handler. Can you help? – vibs2006 Feb 06 '17 at 13:22
  • 1
    Why the ";" after fileName. response.AddHeader("Content-Disposition", "attachment; filename=" + fileName + ";"); – CREM Jun 14 '17 at 19:48
  • 1
    Any difference having this on .aspx than .ashx. I have an exemple that downloads using.aspx and a standalone page, but doesn't works when wrapping the site on another – CREM Jun 14 '17 at 19:54
  • 4
    I am getting an error in `Server.MapPath()` : `Server` in the event handler – Si8 Dec 09 '20 at 16:50
  • 1
    @Si8 try making it context.Server. – JosephStyons Jul 29 '22 at 01:14
13

Try this set of code to download a CSV file from the server.

byte[] Content= File.ReadAllBytes(FilePath); //missing ;
Response.ContentType = "text/csv";
Response.AddHeader("content-disposition", "attachment; filename=" + fileName + ".csv");
Response.BufferOutput = true;
Response.OutputStream.Write(Content, 0, Content.Length);
Response.End();
Si8
  • 9,141
  • 22
  • 109
  • 221
Robin Joseph
  • 1,210
  • 1
  • 11
  • 12
3

Making changes as below and redeploying on server content type as

Response.ContentType = "application/octet-stream";

This worked for me.

Response.Clear(); 
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name); 
Response.AddHeader("Content-Length", file.Length.ToString()); 
Response.ContentType = "application/octet-stream"; 
Response.WriteFile(file.FullName); 
Response.End();
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
2

Further to Karl Anderson solution, you could put your parameters into session information and then clear them after response.TransmitFile(Server.MapPath( Session(currentSessionItemName)));.

See MSDN page HttpSessionState.Add Method (String, Object) for more information on sessions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

None of these worked for me on ASP.NET 6.0 MVC Razor

Example within a controller class add this:

using Microsoft.AspNetCore.Mvc;

public class HomeController : Controller
{
/// <summary>
/// Creates a download file stream for the user.
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public IActionResult Download([FromQuery] string fileName)
{
    var filePath = "[...path to file...]";

    var fs = new FileStream(filePath, FileMode.Open);

    return File(fs, "application/[... content type...]", fileName);
}
}

Example within the view .cshtml file:

<a href="@Url.Action("Download", "Home", new { fileName = quote.fileName })">Download File</a>
MrPlow254
  • 63
  • 1
  • 1
  • 8
1
protected void DescargarArchivo(string strRuta, string strFile)
{
    FileInfo ObjArchivo = new System.IO.FileInfo(strRuta);
    Response.Clear();
    Response.AddHeader("Content-Disposition", "attachment; filename=" + strFile);
    Response.AddHeader("Content-Length", ObjArchivo.Length.ToString());
    Response.ContentType = "application/pdf";
    Response.WriteFile(ObjArchivo.FullName);
    Response.End();


}
trifolius
  • 51
  • 1
  • 1
  • 6
1

Simple solution for downloading a file from the server:

protected void btnDownload_Click(object sender, EventArgs e)
        {
            string FileName = "Durgesh.jpg"; // It's a file name displayed on downloaded file on client side.

            System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
            response.ClearContent();
            response.Clear();
            response.ContentType = "image/jpeg";
            response.AddHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
            response.TransmitFile(Server.MapPath("~/File/001.jpg"));
            response.Flush();
            response.End();
        }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Durgesh Pandey
  • 2,314
  • 4
  • 29
  • 43