使用Asp.net核心将PDF返回到浏览器

Sho*_*ba 19 asp.net file asp.net-core

我在ASP.Net核心中创建了Wep API以返回PDF.这是我的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

但它只返回JSON响应:

{
   "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
}
Run Code Online (Sandbox Code Playgroud)

我在这里做错了吗?

Cod*_*ter 53

ASP.NET Core HTTPRequestMessage中所述,返回奇怪的JSON消息,ASP.NET Core不支持返回HttpResponseMessage(您安装了哪些软件包以访问该类型?).

因此,序列化程序只是将所有公共属性写入HttpResponseMessage输出,就像使用任何其他不受支持的响应类型一样.

要支持自定义响应,您必须返回IActionResult-implementing类型.有很多这些.在你的情况下,我会调查FileStreamResult:

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

或者只需使用a PhysicalFileResult,为您处理流:

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

当然,使用辅助方法可以简化所有这些,例如Controller.File():

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

这简单地抽象了a FileContentResultFileStreamResult(对于这个重载,后者)的创建.

或者,如果您要转换较旧的MVC或Web API应用程序并且不想一次转换所有代码,请添加对WebApiCompatShim(NuGet)的引用,并将当前代码包装在ResponseMessageResult:

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

    return new ResponseMessageResult(response);
}
Run Code Online (Sandbox Code Playgroud)

如果您不想使用return File(fileName, contentType, fileDownloadName),FileStreamResult则不支持从构造函数或通过属性设置content-disposition标头.

在这种情况下,您必须在返回文件结果之前自己将响应标头添加到响应中:

var contentDisposition = new ContentDispositionHeaderValue("attachment");
contentDisposition.SetHttpFileName("foo.txt");
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
Run Code Online (Sandbox Code Playgroud)


小智 6

由于我的声誉不够高,我无法评论CodeCaster的答案。尝试时

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

我们有一个

ObjectDisposedException:无法访问已处置的对象。对象名称:“无法访问关闭的文件。”。System.IO.FileStream.BeginRead(byte []数组,int偏移量,int numBytes,AsyncCallback回调,对象状态)

我们删除了使用

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

那行得通。这是在IIS Express中运行的ASP.NET Core 2.1。


Con*_*ver 5

我没有足够的声誉来发布此评论,因此发布为答案。@CodeCaster 的前 3 个解决方案和 @BernhardMaertl 的解决方案是正确的。

然而,对于那些可能不经常使用文件的人(比如我),请注意,如果运行此代码的进程(例如API)仅具有文件的读取权限,则需要在创建时将其指定为第三个参数您的FileStream,否则默认行为是打开文件进行读/写,并且您将收到异常,因为您没有写权限。

@CodeCaster 的第三个解决方案如下所示:

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