ASP.Net Core Web APIのファイルを返す


131

問題

ASP.Net Web APIコントローラーでファイルを返したいのですが、すべてのアプローチでHttpResponseMessageJSONとして返します。

これまでのコード

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

回答:


228

これが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
[OK]を、見つけ私の私のコントローラは、.NETのコア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.Fileます。
Nkosi

2
あなたの答えはまだ有効です。だから、落胆を感じないでください。答えを裏付けるために使用できるリソースをいくつか指摘していました。
Nkosi

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

注意:

必ず使用してくださいFileStreamResultからMicrosoft.AspNetCore.MvcではないからSystem.Web.Mvc

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.