Kembalikan file di ASP.Net Core Web API

132

Masalah

Saya ingin mengembalikan file di ASP.Net Web API Controller, tetapi semua pendekatan saya mengembalikan HttpResponseMessage sebagai JSON.

Kode sejauh ini

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

Saat saya memanggil titik akhir ini di browser saya, Web API mengembalikan HttpResponseMessagesebagai JSON dengan HTTP Content Header disetel ke application/json.

Jan Kruse
sumber

Jawaban:

230

Jika ini adalah ASP.net-Core maka Anda mencampurkan versi web API. Minta tindakan mengembalikan turunan IActionResultkarena dalam kode Anda saat ini, kerangka kerja memperlakukannya HttpResponseMessagesebagai model.

[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
    }    
}
Nkosi
sumber
12
Dalam kasus saya, saya perlu merender Excel dalam memori dan mengembalikannya untuk diunduh, jadi saya perlu menentukan nama file dengan ekstensi juga: return File(stream, "application/octet-stream", "filename.xlsx"); Dengan cara ini ketika mengunduh pengguna dapat membukanya secara langsung.
KMJungersen
Saya mengerti apa yang NotFound()akhirnya dilakukan, tetapi apakah itu berada di .NET Core atau itu sesuatu yang lokal untuk proyek Anda?
ΩmegaMan
2
@ ΩmegaMan itu adalah metode pembantu ControllerBasedan merupakan bagian dari kerangka itu sendiri docs.microsoft.com/en-us/dotnet/api/…
Nkosi
3
Ok, menemukan masalah saya , meskipun pengontrol saya bekerja di .NET Core 2.2, itu tidak berasal dari kelas dasar Controllersehingga tidak memiliki akses ke ControllerBase.NotFound()metode. Setelah diturunkan, semuanya berhasil. lol / thx
ΩmegaMan
1
Apakah metode ini menghabiskan memori sistem jika Anda mengunduh file besar dari server? Tebakan pertama saya tidak, mengingat fakta bahwa kami tidak membuat MemoryStream () baru. Saya menghargai jawabannya. thx
Ehsan Najafi
18

Anda dapat mengembalikan FileResult dengan metode ini:

1: Kembalikan 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: Kembalikan 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
        };
    }
Hamed Naeemaei
sumber
2
Jika di dalam ControllerBaseada banyak versi ControllerBase.Filehelper kelebihan beban yang mengembalikan salah satu dari versi tersebut.
Nkosi
2
Jawaban Anda masih valid. Jadi jangan merasa kecil hati. Saya baru saja menunjukkan beberapa sumber yang dapat Anda gunakan untuk mendukung jawaban Anda.
Nkosi
1
Ya ini benar.
Hamed Naeemaei
10

Berikut adalah contoh sederhana streaming file:

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

catatan:

Pastikan untuk menggunakan FileStreamResultdari Microsoft.AspNetCore.Mvcdan bukan dari System.Web.Mvc.

gpresland.dll
sumber