【问题标题】:Return PDF to the Browser using ASP.NET Core使用 ASP.NET Core 将 PDF 返回到浏览器
【发布时间】:2017-03-22 01:13:26
【问题描述】:

我在 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;
}

但它只返回 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
}

我在这里做错了吗?

【问题讨论】:

    标签: asp.net file asp.net-core


    【解决方案1】:

    ASP.NET Core HTTPRequestMessage returns strange JSON message 中所述,ASP.NET Core 不支持返回 HttpResponseMessage(您安装了什么包来访问该类型?)。

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

    要支持自定义响应,您必须返回 IActionResult-implementing 类型。有plenty of those。在你的情况下,我会调查FileStreamResult

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

    或者简单地使用PhysicalFileResult,为您处理流:

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

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

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

    这只是抽象了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);
    }
    

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

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

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

    【讨论】:

    • 它也不起作用。 Asp.net Core 不支持 System.Net.Mime.ContentDisposition。
    • 当我使用它时它的工作返回 File(System.IO.File.OpenRead("full-file-path"), contentType: "application/pdf");谢谢 CodeCaster..
    • 不幸的是,这只适用于文件。如果你只有字节数组,使用MemoryStream 似乎不起作用。
    • 谢谢,这是一个很好的答案!按照建议深入了解IActionResult-implementing 类型确实很有帮助。例如。我能够使用FileContentResult 返回一个没有文件名的byte[],并使用ContentResult 返回一个带有ContentType 和StatusCode 的string 内容。
    • @Alisson for byte 数组你可以做Stream stream = new MemoryStream(bytes);
    【解决方案2】:

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

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

    我们有一个

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

    我们删除了使用

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

    这很奏效。这是在 IIS Express 中运行的 ASP.NET Core 2.1。

    【讨论】:

    • 是的。这是返回大文件的正确方法。
    【解决方案3】:

    我没有足够的声誉将此作为评论发布,因此作为答案发布。 @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");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-02
      • 2010-10-18
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      • 2019-01-07
      • 2023-03-25
      相关资源
      最近更新 更多