Trả lại tệp trong API Web lõi của ASP.Net


130

Vấn đề

Tôi muốn trả về một tệp trong Trình điều khiển API Web của ASP.Net, nhưng tất cả các cách tiếp cận của tôi đều trả về HttpResponseMessagedưới dạng JSON.

Mã cho đến nay

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

Khi tôi gọi điểm cuối này trong trình duyệt của mình, API Web trả về HttpResponseMessagedưới dạng JSON với Tiêu đề nội dung HTTP được đặt thành application/json.

Câu trả lời:


226

Nếu đây là ASP.net-Core thì bạn đang trộn các phiên bản API web. Có hành động trả về một dẫn xuất IActionResultbởi vì trong mã hiện tại của bạn, khung công tác đang xử lý HttpResponseMessagenhư một mô hình.

[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
Trong trường hợp của tôi, tôi cần kết xuất Excel trong bộ nhớ và trả lại để tải xuống, vì vậy tôi cũng cần xác định tên tệp có phần mở rộng: return File(stream, "application/octet-stream", "filename.xlsx"); Cách này khi tải xuống, người dùng có thể mở trực tiếp.
KMJungersen

Tôi hiểu những gì NotFound()cuối cùng làm, nhưng nó nằm trong .NET Core hay nó là một cái gì đó cục bộ cho dự án của bạn?
ΩmegaMan

2
@ ΩmegaMan, đây là một phương thức trợ giúp ControllerBasevà là một phần của khung công tác docs.microsoft.com/en-us/dotnet/api/ Kẻ
Nkosi

3
Ok, đã tìm thấy vấn đề của tôi , mặc dù bộ điều khiển của tôi đang hoạt động trong .NET Core 2.2, nhưng nó không xuất phát từ lớp cơ sở Controllerdo đó không có quyền truy cập vào ControllerBase.NotFound()phương thức. Sau khi bắt nguồn, tất cả đều hoạt động. lol / thx
ΩmegaMan

1
Phương pháp này có chiếm bộ nhớ hệ thống trong trường hợp bạn đang tải xuống các tệp lớn từ máy chủ không? Dự đoán đầu tiên của tôi là không, với thực tế là chúng tôi sẽ không tạo ra một MemoryStream () mới. Tôi đánh giá cao một câu trả lời. thx
Ehsan Najafi

16

Bạn có thể trả về FileResult bằng các phương thức này:

1: Trả lại 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: Trả về 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
Nếu trong phạm vi ControllerBasecó nhiều phiên bản ControllerBase.Filetrợ giúp quá tải trả về bất kỳ một trong số đó.
Nkosi

2
Câu trả lời của bạn vẫn còn hiệu lực. Vì vậy, đừng cảm thấy chán nản. Tôi chỉ chỉ ra một số tài nguyên bạn có thể sử dụng để hỗ trợ câu trả lời của bạn.
Nkosi

1
Đúng vậy đây là sự thật.
Hamed Naeemaei

9

Đây là một ví dụ đơn giản về truyền phát tệp:

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");
}

Ghi chú:

Hãy chắc chắn để sử dụng FileStreamResulttừ Microsoft.AspNetCore.Mvckhông từ System.Web.Mvc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.