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?

4
  • 1
    can you share the code which you used to call this method ? Commented Oct 22, 2012 at 6: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). Commented Aug 29, 2014 at 16:46
  • what's happening inside the GetMyForm()? Converting the files into stream of bytes? Commented Feb 21, 2018 at 19:35
  • @MSIslam Sort of. The function gets information from user's form and creates a file before converting to the resulting stream. Commented Feb 22, 2018 at 18:58

9 Answers 9

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"
};
Sign up to request clarification or add additional context in comments.

6 Comments

For anyone curious about the "attachment" disposition type, the full list of disposition types is at iana.org/assignments/cont-disp/cont-disp.xhtml
You have another answer to downloading a file here. Does it matter whether you use System.Net.Mime.ContentDisposition or ContentDispositionHeaderValue? Is one more current and more preferred than the other?
@Luminous one answer is for ActionResult, one's for HttpResponseMessage
@Luminous "Does it matter" and "Is one more current and more preferred than the other?" No, and no. One is for MVC ActionResults, and one is for WebApi HttpResponseMessages.
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.
|
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.

3 Comments

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.
Doesn't cover escaping. What if the file name includes a ; or something else with a special meaning?
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.
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.

Comments

6

I think that this might be helpful to you.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)

1 Comment

Doesn't cover escaping. What if the file name includes a ; or something else with a special meaning?
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;

1 Comment

Doesn't cover escaping. What if the file name includes a ; or something else with a special meaning?
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}");

1 Comment

Doesn't cover escaping. What if the file name includes a ; or something else with a special meaning?
2

This should do:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)

1 Comment

Doesn't cover escaping. What if the file name includes a ; or something else with a special meaning?
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.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.