ส่งคืนไฟล์ใน ASP.Net Core Web API


132

ปัญหา

ฉันต้องการส่งคืนไฟล์ใน ASP.Net Web API Controller ของฉัน แต่วิธีการทั้งหมดของฉันกลับ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 ส่งกลับHttpResponseMessageเป็น JSON กับ HTTP application/jsonชุดหัวเนื้อหาเพื่อ

คำตอบ:


231

หากนี่คือ 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()เมธอดได้ เมื่อได้มาแล้วทุกอย่างได้ผล lol / thx
ΩmegaMan

1
วิธีนี้ใช้หน่วยความจำระบบในกรณีที่คุณดาวน์โหลดไฟล์ขนาดใหญ่จากเซิร์ฟเวอร์หรือไม่? ฉันเดาไม่ถูกเนื่องจากข้อเท็จจริงที่ว่าเราไม่ได้สร้าง MemoryStream () ใหม่ ฉันขอขอบคุณสำหรับคำตอบ thx
Ehsan Najafi

18

คุณสามารถส่งคืน 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.Fileซึ่งส่งคืนเวอร์ชันใดเวอร์ชันหนึ่ง
Nkosi

2
คำตอบของคุณยังใช้ได้ ดังนั้นอย่ารู้สึกท้อแท้ ฉันแค่ชี้ให้เห็นแหล่งข้อมูลบางอย่างที่คุณสามารถใช้เพื่อสนับสนุนคำตอบของคุณ
Nkosi

1
ใช่นี่เป็นเรื่องจริง
Hamed Naeemaei

10

นี่คือตัวอย่างง่ายๆของการสตรีมไฟล์:

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

บันทึก:

ตรวจสอบการใช้FileStreamResultจากMicrosoft.AspNetCore.Mvcและไม่ได้System.Web.Mvcจาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.