【问题标题】:ActionResult<FileResult> doesn't work as expectedActionResult<FileResult> 没有按预期工作
【发布时间】:2018-09-24 19:06:45
【问题描述】:

我正在使用 ASP.NET Core 2.1 ActionResult 从控制器返回一个文件:

[HttpGet]
public ActionResult<FileResult> Download()
{
    var someBinaryFile = "somebinaryfilepath";
    return File(new FileStream(firstExe, FileMode.Open, FileAccess.Read, FileShare.Read), System.Net.Mime.MediaTypeNames.Application.Octet, true);
}

但它返回不完整的 json 而不是开始下载文件:

{"fileStream":{"handle":{"value":2676},"canRead":true,"canWrite":false,"safeFileHandle":
{"isInvalid":false,"isClosed":false},"name":"somebinaryfilepath","isAsync":false,"length":952320,"position":0,"canSeek":true,"canTimeout":false

Chrome devtools 将请求状态指示为“(失败)”,工具提示为“net::ERR_SPDY_PROTOCOL_ERROR”

如果我更改代码使其返回 FileContentResult,则状态变为“200 ok”,但仍写入 json 而不是文件下载:

{"fileContents": "somebinaryfilecontent","contentType":"application/octet-stream","fileDownloadName":"","lastModified":null,"entityTag":null,"enableRangeProcessing":true}

如果我将方法签名更改为

public FileResult Download()

或者去

public IActionResult Download()

然后文件下载从两个 FileResult 实现开始。

如何使用 ActionResult 下载文件?我错过了什么还是真的是某种错误?

【问题讨论】:

    标签: c# asp.net-core asp.net-core-2.1


    【解决方案1】:

    当使用ActionResult&lt;T&gt; 时,在这种情况下T 是您要返回的specific type。默认情况下,当直接或使用 ActionResult&lt;T&gt; 从操作返回时,此类型将序列化为 JSON,正如您在问题中所展示的那样。

    对于您的示例,您根本不返回特定类型,您将希望使用IActionResult(如您所见,根据您的问题),如下所示:

    [HttpGet]
    public IActionResult Download()
    {
        ...
    }
    

    您也可以使用ActionResultFileResultFileStreamResult,但首选IActionResult


    这是为什么我认为首先会发生这种情况的解释。

    ActionResult&lt;T&gt; 包含两个隐式运算符:

    public static implicit operator ActionResult<TValue>(TValue value)
    {
        return new ActionResult<TValue>(value);
    }
    
    public static implicit operator ActionResult<TValue>(ActionResult result)
    {
        return new ActionResult<TValue>(result);
    }
    

    在您的示例中,当返回 FileStreamResult 时,可以使用这两个隐式运算符。一个在 any 类型 (TValue) 上运行,另一个在 ActionResult 上运行。我希望 C# 编译器选择第一个版本,因为 TValue (FileResult) 是 FileStreamResult(您的实际返回值)的更好匹配。

    这在“11.5.4 用户定义的隐式转换”部分下的C# spec 中有介绍。具体来说,我认为这是适用的描述(我不是这里的专家):

    在 U 中找到最具体的源类型 SX:

    • 如果 S 存在且 U 中的任何运算符都从 S 转换,则 SX 是 S。
    • 否则,SX 是 U 中运算符的源类型组合集合中最广泛的类型。如果找不到恰好一个最广泛的类型,则转换不明确并发生编译时错误。

    在这种情况下,FileResult最具体的源类型(它比ActionResult 更具体)。

    【讨论】:

      猜你喜欢
      • 2021-10-19
      • 2020-03-18
      • 2012-06-14
      • 2014-11-15
      • 1970-01-01
      • 2012-07-02
      • 2011-09-07
      • 2013-03-03
      • 2015-05-18
      相关资源
      最近更新 更多