58

I created the Wep API in ASP.Net core to return the PDF. Here is my code:

public HttpResponseMessage Get(int id)
{
    var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);           
    var stream = new System.IO.FileStream(@"C:\Users\shoba_eswar\Documents\REquest.pdf", System.IO.FileMode.Open);
    response.Content = new StreamContent(stream);
    response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    response.Content.Headers.ContentDisposition.FileName = "NewTab";
    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
    return response;
}

But it returns only the JSON response:

{
   "version":{
      "major":1,
      "minor":1,
      "build":-1,
      "revision":-1,
      "majorRevision":-1,
      "minorRevision":-1
   },
   "content":{
      "headers":[
         {
            "key":"Content-Disposition",
            "value":[
               "attachment; filename=NewTab"
            ]
         },
         {
            "key":"Content-Type",
            "value":[
               "application/pdf"
            ]
         }
      ]
   },
   "statusCode":200,
   "reasonPhrase":"OK",
   "headers":[

   ],
   "requestMessage":null,
   "isSuccessStatusCode":true
}

Am I doing anything wrong here?

0

3 Answers 3

133

As explained in ASP.NET Core HTTPRequestMessage returns strange JSON message, ASP.NET Core does not support returning an HttpResponseMessage (what package did you install to get access to that type?).

Because of this, the serializer is simply writing all public properties of the HttpResponseMessage to the output, as it would with any other unsupported response type.

To support custom responses, you must return an IActionResult-implementing type. There's plenty of those. In your case, I'd look into the FileStreamResult:

public IActionResult Get(int id)
{
    var stream = new FileStream(@"path\to\file", FileMode.Open);
    return new FileStreamResult(stream, "application/pdf");     
}

Or simply use a PhysicalFileResult, where the stream is handled for you:

public IActionResult Get(int id)
{
    return new PhysicalFileResult(@"path\to\file", "application/pdf");
}

Of course all of this can be simplified using helper methods, such as Controller.File():

public IActionResult Get(int id)
{
    var stream = new FileStream(@"path\to\file", FileMode.Open);
    return File(stream, "application/pdf", "FileDownloadName.ext");
}

This simply abstracts the creation of a FileContentResult or FileStreamResult (for this overload, the latter).

Or if you're converting an older MVC or Web API application and don't want to convert all your code at once, add a reference to WebApiCompatShim (NuGet) and wrap your current code in a ResponseMessageResult:

public IActionResult Get(int id)
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);           
    var stream = ...
    response.Content...

    return new ResponseMessageResult(response);
}

If you don't want to use return File(fileName, contentType, fileDownloadName), then the FileStreamResult doesn't support setting the content-disposition header from the constructor or through properties.

In that case you'll have to add that response header to the response yourself before returning the file result:

var contentDisposition = new ContentDispositionHeaderValue("attachment");
contentDisposition.SetHttpFileName("foo.txt");
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
Sign up to request clarification or add additional context in comments.

6 Comments

Its also not working. System.Net.Mime.ContentDisposition not supported in the Asp.net Core.
Its Working when i Use this return File(System.IO.File.OpenRead("full-file-path"), contentType: "application/pdf"); Thank you CodeCaster..
Unfortunately this only works for files. If you only have the byte array, using MemoryStream doesn't seem to work.
Thanks, this is a great answer! It really helps to drill down through the IActionResult-implementing types as recommended. E.g. I was able use FileContentResult to return a byte[] without a filename and ContentResult to return a string content with ContentType and StatusCode.
@Alisson for byte array you can do Stream stream = new MemoryStream(bytes);
|
8

I couldn't comment the answer by CodeCaster since my reputation isn't high enough. When trying

public IActionResult Get(int id)
{
    using (var stream = new FileStream(@"path\to\file", FileMode.Open))
    {
        return File(stream, "application/pdf", "FileDownloadName.ext");
    }       
} 

we got a

ObjectDisposedException: Cannot access a disposed object. Object name: 'Cannot access a closed file.'. System.IO.FileStream.BeginRead(byte[] array, int offset, int numBytes, AsyncCallback callback, object state)

We removed the using

   [HttpGet]
   [Route("getImageFile")]
   public IActionResult GetWorkbook()
   {
        var stream = new FileStream(@"pathToFile", FileMode.Open);
        return File(stream, "image/png", "image.png");
   }

And that worked. This is ASP.NET Core 2.1 running in IIS Express.

1 Comment

Yes. This is the correct way of returning a huge file.
5

I don't have enough reputation to post this as a comment, so posting as an answer. The first 3 solutions from @CodeCaster and the solution from @BernhardMaertl are correct.

However, for someone who may not work with files often (like me), please note that if the process running this code (e.g. the API) only has read permissions to the file, you will need to specify that as the third parameter when creating your FileStream, otherwise the default behavior is to open the file for read/write and you will get an exception since you do not have write permissions.

The 3rd solution from @CodeCaster would then look like this:

public IActionResult Get(int id)
{
    var stream = new FileStream(@"path\to\file", FileMode.Open, FileAccess.Read);
    return File(stream, "application/pdf", "FileDownloadName.ext");
}

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.