149

In my ApiController class, I have following method to download a file created by server.

public HttpResponseMessage Get(int id)
{
    try
    {
        string dir = HttpContext.Current.Server.MapPath("~"); //location of the template file
        Stream file = new MemoryStream();
        Stream result = _service.GetMyForm(id, dir, file);
        if (result == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        result.Position = 0;
        HttpResponseMessage response = new HttpResponseMessage();
        response.StatusCode = HttpStatusCode.OK;
        response.Content = new StreamContent(result);
        return response;
    }
    catch (IOException)
    {
        return Request.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

Everything is working perfect except that default downloading file name is its id so user might have to type his/her own file name at save as dialog each time. Is there any way to set a default file name in the code above?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Tae-Sung Shin
  • 20,215
  • 33
  • 138
  • 240
  • 1
    can you share the code which you used to call this method ? – Yasser Shaikh Oct 22 '12 at 06:18
  • @Yasser - this is a web API controller method - it's probably getting called via HTTP requests coming into IIS and parsing them and finding routes and web API calling the method (and, of course, it's also being called by tests). – Dave Rael Aug 29 '14 at 16:46
  • what's happening inside the GetMyForm()? Converting the files into stream of bytes? – MSIslam Feb 21 '18 at 19:35
  • @MSIslam Sort of. The function gets information from user's form and creates a file before converting to the resulting stream. – Tae-Sung Shin Feb 22 '18 at 18:58

9 Answers9

308

You need to set the Content-Disposition header on the HttpResponseMessage:

HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(result);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = "foo.txt"
};
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 23
    For anyone curious about the "attachment" disposition type, the full list of disposition types is at http://www.iana.org/assignments/cont-disp/cont-disp.xhtml – sfuqua Sep 30 '14 at 18:56
  • 1
    You have another answer to [downloading a file here.](http://stackoverflow.com/questions/5826649/returning-a-file-to-view-download-in-mvc) Does it matter whether you use `System.Net.Mime.ContentDisposition` or `ContentDispositionHeaderValue`? Is one more current and more preferred than the other? – Luminous May 08 '15 at 16:00
  • @Luminous one answer is for `ActionResult`, one's for `HttpResponseMessage` – weston May 20 '15 at 14:09
  • @weston your response doesn't answer the my question. – Luminous May 20 '15 at 17:20
  • 4
    @Luminous "Does it matter" and "Is one more current and more preferred than the other?" No, and no. One is for MVC `ActionResult`s, and one is for WebApi `HttpResponseMessage`s. – weston May 21 '15 at 14:52
  • 1
    I used this with 'inline' instead of 'attachment' as per the link @sfuqua provided and it works great. e.g. PDFs shown in the browser and Word documents downloaded etc. – Chris Snowden Oct 25 '16 at 10:10
28

EDIT: As mentioned in a comment, My answer doesn't account for characters that need to be escaped like a ;. You should use the accepted answer Darin made if your file name could contain a semi-colon.

Add a Response.AddHeader to set the file name

Response.AddHeader("Content-Disposition", "attachment; filename=*FILE_NAME*");

Just change FILE_NAME to the name of the file.

AndyC
  • 1,325
  • 1
  • 13
  • 23
  • 2
    This proved helpful for me in solving a similar problem to the question asker. In my case, I also found it useful to change "attachment" to "inline" so that IE8 would give me the option to always open the file type in question. – Scott May 22 '13 at 19:27
  • 2
    Doesn't cover escaping. What if the file name includes a `;` or something else with a special meaning? – Sam Jun 22 '15 at 04:54
  • Sam, At the time I wrote this answer 3 years ago I didn't realize my answer needed to handle escaping. Thank you for pointing this out to me, I made an edit to my answer explaining my answer doesn't account for escaping. But keeping my answer the same since it seemed to have helped people. – AndyC Jun 23 '15 at 16:58
10

If you want to ensure that the file name is properly encoded but also avoid the WebApi HttpResponseMessage you can use the following:

Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition("attachment") { FileName = "foo.txt" }.ToString());

You may use either ContentDisposition or ContentDispositionHeaderValue. Calling ToString on an instance of either will do the encoding of file names for you.

sorenhk
  • 1,597
  • 15
  • 9
6

I think that this might be helpful to you.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)
Jarek
  • 3,359
  • 1
  • 27
  • 33
  • 4
    Doesn't cover escaping. What if the file name includes a `;` or something else with a special meaning? – Sam Jun 22 '15 at 04:54
3

You need to add the content-disposition header to the response:

 response.StatusCode = HttpStatusCode.OK;
 response.Content = new StreamContent(result);
 response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
 return response;
Carl Raymond
  • 4,429
  • 2
  • 25
  • 39
  • 3
    Doesn't cover escaping. What if the file name includes a `;` or something else with a special meaning? – Sam Jun 22 '15 at 04:54
3

If you are using ASP.NET Core MVC, the answers above are ever so slightly altered...

In my action method (which returns async Task<JsonResult>) I add the line (anywhere before the return statement):

Response.Headers.Add("Content-Disposition", $"attachment; filename={myFileName}");
Peter
  • 971
  • 11
  • 12
2

This should do:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
tucaz
  • 6,524
  • 6
  • 37
  • 60
  • 2
    Doesn't cover escaping. What if the file name includes a `;` or something else with a special meaning? – Sam Jun 22 '15 at 04:56
1

Considering the previous answers, it is necessary to be careful with globalized characters.

Suppose the name of the file is: "Esdrújula prenda ñame - güena.jpg"

Raw result to download: "Esdrújula prenda ñame - güena.jpg" [Ugly]

HtmlEncode result to download: "Esdr&_250;jula prenda &_241;ame - g&_252;ena.jpg" [Ugly]

UrlEncode result to download: "Esdrújula+prenda+ñame+-+güena.jpg" [OK]

Then, you need almost always to use the UrlEncode over the file name. Moreover, if you set the content-disposition header as direct string, then you need to ensure surround with quotes to avoid browser compatibility issues.

Response.AddHeader("Content-Disposition", $"attachment; filename=\"{HttpUtility.UrlEncode(YourFilename)}\"");

or with class aid:

var cd = new ContentDisposition("attachment") { FileName = HttpUtility.UrlEncode(resultFileName) };
Response.AddHeader("Content-Disposition", cd.ToString());

The System.Net.Mime.ContentDisposition class takes care of quotes.

Asereware
  • 1,009
  • 6
  • 7
0

Note: The last line is mandatory.

If we didn't specify Access-Control-Expose-Headers, we will not get File Name in UI.

FileInfo file = new FileInfo(FILEPATH);

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = file.Name
};
response.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
Chandan Y S
  • 968
  • 11
  • 21