13

My previous question: How to return file from ASP.net 5 web api

I am trying to return a file as the response from Web API POST request.

I'm using dnx451 framework and rc1-final build. Controller method:

[HttpPost("")]
public ActionResult Post([FromBody]DocumentViewModel vm)
{
    try
    {
        if (ModelState.IsValid)
        {

            var Document = _repository.GetDocumentByGuid(vm.DocumentGuid, User.Identity.Name);
            var Params = Helper.ClientInputToRealValues(vm.Parameters, Document.DataFields);
            var file = Helper.GeneratePdf(Helper.InsertValues(Params, Document.Content));
            FileStream stream = new FileStream(file,FileMode.Open);

            return File(stream, "application/pdf", "test.pdf");

        }

    }
    catch (Exception ex)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return null;
    }
    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    return null;

}

As result I get a file with name "response". After saving it as pdf i try to open it, and it says it is damaged. Hope you can help me. I am using Postman as test client.

Thanks

Community
  • 1
  • 1
Joonas Püüa
  • 370
  • 3
  • 5
  • 18
  • When you debug this, does the code reach the `return File()` line? What is the content and headers received in the response? – David Jan 18 '16 at 14:38
  • Is your `Helper.GeneratePdf()` line doing its work correctly? What is the value of `file`? Can the file be opened, and did you inspected the file being generated before sending it back to the browser? – Leonardo Herrera Jan 18 '16 at 14:47
  • yes the pdf is generated, and I can open generated pdf file from File explorer and it is just fine. – Joonas Püüa Jan 18 '16 at 14:48

3 Answers3

25

Please see my answer in the other post: Return file as response

For reference, I think this fits your needs:

public FileResult TestDownload()
{
    HttpContext.Response.ContentType = "application/pdf";
    FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes("YOUR PATH TO PDF"), "application/pdf")
    {
        FileDownloadName = "test.pdf"
    };

    return result;                                
}
Community
  • 1
  • 1
Ian Auty
  • 847
  • 7
  • 10
  • The result is still the same. Response returns file called "response". if i rename it to somthing.pdf and try to open it - it is still damaged. – Joonas Püüa Jan 18 '16 at 14:37
  • I have tested that code locally with a local pdf and the file downloaded properly and I could open it. Is the pdf path local to your machine, or are you generating it dynamically or something? Where I've stated 'YOUR PATH TO PDF', you must include the extension also. – Ian Auty Jan 18 '16 at 14:39
  • basically I am creating it but atm I am testing with local file. yes .pdf is included. I think it could be PostMan issue. – Joonas Püüa Jan 18 '16 at 14:48
  • Quite possibly, to confirm the code works for you with your PDF you could create a new MVC project and just add that method to the HomeController.cs that's generated for you. That's what I did to test before posting. Then you can find out the culprit from there :) – Ian Auty Jan 18 '16 at 14:53
  • So basicly I will make my own test client, as postman is not up to it or atleast i have no idea how it should work with it, Thanks – Joonas Püüa Jan 18 '16 at 15:01
  • 1
    FileResult and FileContentResult are Mvc classes, that's not Webapi – Boanerge Jul 19 '18 at 19:14
  • This requires importing `System.Web.Mvc`, which will break everything else in a WebAPI controller. The question was about WebAPI. – Florian Winter Jul 30 '19 at 10:51
  • This answer was added over 3 years ago. ASP.NET Core has changed a lot over that time. I suggest you add a separate answer if you do not believe this to be correct. – Ian Auty Jul 31 '19 at 11:17
12

I've just had this problem and found a solution. As long as you have an absolute path to your file, then you can return a PhysicalFileResult and explicitly set the Content-Disposition header on the Response, like so:

[HttpGet("{key}")]
public IActionResult Get(string key)
{
    var file = _files.GetPath(key);

    var result = PhysicalFile(file.Path, "text/text");

    Response.Headers["Content-Disposition"] = new ContentDispositionHeaderValue("attachment")
    {
        FileName = file.Name
    }.ToString();

    return result;
}

Using PhysicalFile also has the advantage that all the asynchronous streaming of bytes and so on is taken care of by the framework.

Mark Rendle
  • 9,274
  • 1
  • 32
  • 58
2

It's perhaps better to consider the use the FileStreamResult action result.

This has the advantage of not requiring that the entire file contents be held in memory which, depending on the size of the file, level of traffic, etc. could very easily lead to problems of scale.

Something like this:

[HttpGet]
public FileStreamResult DownloadFile()
{
    var Document = _repository.GetDocumentByGuid(vm.DocumentGuid, User.Identity.Name);
    var Params = Helper.ClientInputToRealValues(vm.Parameters, Document.DataFields);
    var file = Helper.GeneratePdf(Helper.InsertValues(Params, Document.Content));
    var stream = new FileStream(file,FileMode.Open);
    return new FileStreamResult(stream, "application/pdf")
    {
        FileDownloadName = "test.pdf"
    };
}
Jnr
  • 1,504
  • 2
  • 21
  • 36
Stewart_R
  • 13,764
  • 11
  • 60
  • 106