1

I try to create a simple WebAPI controller in .NET Framework 4.7.1 with one GET Endpoint which return a file (in these case a PDF), but when I call it, it return a JSON with the request info instead. I can't figure why, could you tell me where is my mistake please?

I tried returning different HttpContent such as StreamContent or ByteArrayContent, trying to replicate the response from How to return a file (FileContentResult) in ASP.NET WebAPI or https://www.aspsnippets.com/Articles/Return-Download-File-using-Web-API-in-ASPNet-MVC.aspx but it always seems to end with the same request info.

[HttpGet]
[Route("GetReport")]
public HttpResponseMessage GetReport()
{
     FileStream stream = System.IO.File.Open(PDF_TEMP_PATH, FileMode.Open);

     var result = new HttpResponseMessage(HttpStatusCode.OK)
     {
         Content = new StreamContent(stream)
     };

     result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
     {
         FileName = "test.pdf"
     };

     result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

     return result;
}

Here is the result:

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

But obviously I would like the PDF in the Stream instead.

Rwandrall
  • 21
  • 1
  • 1
  • 5
  • What version of Web API are you using? Core? – Nkosi Jul 02 '19 at 15:10
  • Where did the version information come from? Did you install some filters? – Jeroen Heier Jul 02 '19 at 15:30
  • The version is .NET Framework 4.7.1, i will add the information in the question. I don't know what Jeroen Heier mean with the version information question, could you clarify please? And I didn't install any filter. – Rwandrall Jul 03 '19 at 06:38
  • @Rwandrall where did this JSON string come from? .NET properties **don't** start with lowercase, ever. Did you convert the response to JSON perhaps instead of reading from it? How did you call the Web API method? Post your client code – Panagiotis Kanavos Jul 03 '19 at 08:14
  • 1
    The Json came from the result I got from the navigator as I called the Endpoint. – Rwandrall Jul 03 '19 at 08:39
  • @PanagiotisKanavos you're really mad today, keep calm and be nice with newcomers. By default, ASP.NET Core JSON output is in camelCase. So his properties are probably in PascalCase but the JSON formater converted them to camelCase. – Selmir Jul 03 '19 at 08:47
  • @Selmir the question is about returning a *file* not JSON. 4 others decided to close this question because it doesn't have the actual code that produces the problem. All of them have far higher rep than me, I'm just the one that decided to comment. An answer that simply covers up the problem doesn't help anyone, it causes actual harm – Panagiotis Kanavos Jul 03 '19 at 08:48
  • I don't care about rep (even if yours is really impressive) but the dude had one issue you're asking him about the JSON output format, I agree that the question isn't that clear, but if we can help why not try ? Anyway, thanks for your time and have a nice day :) – Selmir Jul 03 '19 at 08:58
  • Multiple valid answers are posted in [Returning binary file from controller in ASP.NET Web API](https://stackoverflow.com/questions/9541351/returning-binary-file-from-controller-in-asp-net-web-api) – Panagiotis Kanavos Jul 03 '19 at 09:10

2 Answers2

3

Here's what you need

       HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
        {
             Content = new StreamContent(stream),
        };

        result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
        {
            FileName = "Test.pdf"
        };

        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

        return ResponseMessage(result);
Rav
  • 703
  • 4
  • 13
  • 1
    Thank you for your reply, but I can't use ResponseMessage() as the project use .Net Framework 4.7.1 and not Core, I'll modify the question accordingly. I tried to change the ContentType to "application/octet-stream" but i got the same result described in the question. – Rwandrall Jul 03 '19 at 06:31
  • 1
    @Rwandrall that is from .net 4.7, if you were using core you'd be returning an ActionResult – Rav Jul 03 '19 at 08:11
  • @Rwandrall .NET properties never start with lowercase letters. Where did you get that JSON string? Update the question and post the client code. Most likely you're converting the response of a Javascript call to JSON instead of using it – Panagiotis Kanavos Jul 03 '19 at 08:16
0

You can (should?) use ActionResults to return data from your API.

[HttpGet]
[Route("GetReport")]
public ActionResult GetReport()
{
     return File(System.IO.File.OpenRead(PDF_TEMP_PATH), "application/pdf");
}

You'll just have to set your ContentType accordingly.

Another good practice is to make your method async to a void blocking.

Selmir
  • 1,136
  • 1
  • 11
  • 21
  • 1
    `async` has nothing to do with locking – Panagiotis Kanavos Jul 03 '19 at 08:08
  • Thanks @PanagiotisKanavos you're right. I meant blocking instead of locking. – Selmir Jul 03 '19 at 08:16
  • 1
    @Rwandrall no it doesn't, unless this reversed a client-side bug. The duplicates and other answers work. People would have noticed years ago if they didn't. How are you going to set the content type or the disposition with this code? – Panagiotis Kanavos Jul 03 '19 at 08:25
  • @Rwandrall this means that should any code except yours will fail when calling this action, unless it replicates the client-side bug – Panagiotis Kanavos Jul 03 '19 at 08:29
  • @PanagiotisKanavos added a fix for content type :) – Selmir Jul 03 '19 at 08:59
  • @Selmir this is a completely different answer, not a fix for the content type. It returns the actual file, not a JSON string. Unfortunately, [File()](https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.controller.file?view=aspnet-mvc-5.2) is only available in MVC, not Web API. That's why the duplicates and the other answers work with HttpResponseMessage or IHttpActionResult. [This answer creates its own FileResuilt](https://stackoverflow.com/a/20888749/134204) to make things easier. The question's code *works*. `File()` in MVC will return the *same* response too. – Panagiotis Kanavos Jul 03 '19 at 09:08
  • @Selmir this means that the OP will have the same problem with `File()` if it gets converted to JSON, either through a bug in the code, or a filter that converted the raw HTTP response to JSON – Panagiotis Kanavos Jul 03 '19 at 09:08
  • The OP never wanted to return a JSON, but the actual file. Please have a look here (https://odetocode.com/blogs/scott/archive/2018/01/09/streaming-content-in-asp-net-core.aspx) – Selmir Jul 03 '19 at 09:12