在ASP.Net Core Web API中返回文件


130

问题

我想在ASP.Net Web API控制器中返回一个文件,但是我所有的方法都将其返回HttpResponseMessage为JSON。

到目前为止的代码

public async Task<HttpResponseMessage> DownloadAsync(string id)
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = new StreamContent({{__insert_stream_here__}});
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    return response;
}

当我在浏览器中调用此终结点时,Web API会将HttpResponseMessageHTTP内容标头设置为,以JSON形式返回application/json

Answers:


226

如果这是ASP.net-Core,则您正在混合使用Web API版本。让操作返回一个派生,IActionResult因为在您当前的代码中,该框架被HttpResponseMessage视为模型。

[Route("api/[controller]")]
public class DownloadController : Controller {
    //GET api/download/12345abc
    [HttpGet("{id}"]
    public async Task<IActionResult> Download(string id) {
        Stream stream = await {{__get_stream_based_on_id_here__}}

        if(stream == null)
            return NotFound(); // returns a NotFoundResult with Status404NotFound response.

        return File(stream, "application/octet-stream"); // returns a FileStreamResult
    }    
}

12
在我的情况下,我需要在内存中呈现一个Excel并将其返回以供下载,因此我还需要定义一个扩展名为的文件名:return File(stream, "application/octet-stream", "filename.xlsx"); 这样,下载时,用户可以直接打开它。
KMJungersen

我知道NotFound()最终会做什么,但是它驻留在.NET Core中还是在您的项目本地?
ΩmegaMan

2
@ΩmegaMan它是辅助方法,ControllerBase并且是框架本身的一部分docs.microsoft.com/en-us/dotnet/api/…–
Nkosi

3
好的,找到了我的问题,尽管我的控制器在.NET Core 2.2中运行,但它不是从基类派生的,Controller因此无法访问该ControllerBase.NotFound()方法。一旦派生,所有的工作。洛尔/ THX
ΩmegaMan

1
万一您要从服务器下载大文件,此方法是否会占用系统内存?鉴于我们没有创建新的MemoryStream(),因此我的第一个猜测不是。我希望得到一个答案。thx
Ehsan Najafi

16

您可以使用以下方法返回FileResult:

1:返回FileStreamResult

    [HttpGet("get-file-stream/{id}"]
    public async Task<FileStreamResult> DownloadAsync(string id)
    {
        var fileName="myfileName.txt";
        var mimeType="application/...."; 
        var stream = await GetFileStreamById(id);

        return new FileStreamResult(stream, mimeType)
        {
            FileDownloadName = fileName
        };
    }

2:返回FileContentResult

    [HttpGet("get-file-content/{id}"]
    public async Task<FileContentResult> DownloadAsync(string id)
    {
        var fileName="myfileName.txt";
        var mimeType="application/...."; 
        var fileBytes = await GetFileBytesById(id);

        return new FileContentResult(fileBytes, mimeType)
        {
            FileDownloadName = fileName
        };
    }

2
如果在内ControllerBase,有许多重载的ControllerBase.Filehelper 版本将返回其中任何一个。
恩科西

2
您的答案仍然有效。所以不要灰心。我只是指出一些可以用来支持您的答案的资源。
恩科西

1
是的,这是真的。
Hamed Naeemaei

9

这是流式传输文件的一个简单示例:

using System.IO;
using Microsoft.AspNetCore.Mvc;
[HttpGet("{id}")]
public async Task<FileStreamResult> Download(int id)
{
    var path = "<Get the file path using the ID>";
    var stream = File.OpenRead(path);
    return new FileStreamResult(stream, "application/octet-stream");
}

注意:

确保使用FileStreamResultfrom Microsoft.AspNetCore.Mvc不是 from System.Web.Mvc

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.