Rückgabedatei in der ASP.Net Core-Web-API

130

Problem

Ich möchte eine Datei in meinem ASP.Net Web API Controller zurückgeben, aber alle meine Ansätze geben die HttpResponseMessageals JSON zurück.

Code bisher

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

Wenn ich diesen Endpunkt in meinem Browser aufrufe, gibt die Web-API den Wert HttpResponseMessageals JSON mit dem HTTP-Inhaltsheader zurück application/json.

Jan Kruse
quelle

Antworten:

226

Wenn dies ASP.net-Core ist, mischen Sie Web-API-Versionen. Lassen Sie die Aktion eine Ableitung zurückgeben, IActionResultda das Framework in Ihrem aktuellen Code HttpResponseMessageals Modell behandelt wird.

[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
quelle
11
In meinem Fall musste ich ein Excel im Speicher rendern und zum Herunterladen zurückgeben, daher musste ich auch einen Dateinamen mit der Erweiterung definieren: Auf return File(stream, "application/octet-stream", "filename.xlsx"); diese Weise kann der Benutzer es beim Herunterladen direkt öffnen.
KMJungersen
Ich verstehe, was das NotFound()letztendlich bewirkt, aber befindet es sich in .NET Core oder ist es etwas Lokales für Ihr Projekt?
ΩmegaMan
2
@ ΩmegaMan es ist eine Hilfsmethode auf ControllerBaseund ist Teil des Frameworks selbst docs.microsoft.com/en-us/dotnet/api/…
Nkosi
3
Ok, ich habe mein Problem gefunden, obwohl mein Controller in .NET Core 2.2 arbeitete, wurde er nicht von der Basisklasse abgeleitet Controllerund hatte daher keinen Zugriff auf die ControllerBase.NotFound()Methode. Einmal abgeleitet, hat alles funktioniert. lol / thx
ΩmegaMan
1
Verbraucht diese Methode Systemspeicher, wenn Sie große Dateien vom Server herunterladen? Meine erste Vermutung ist nicht, da wir keinen neuen MemoryStream () erstellen. Ich würde mich über eine Antwort freuen. thx
Ehsan Najafi
16

Sie können FileResult mit folgenden Methoden zurückgeben:

1: Geben Sie FileStreamResult zurück

    [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: Geben Sie FileContentResult zurück

    [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
quelle
2
Wenn innerhalb von a ControllerBaseviele überladene Versionen von ControllerBase.Filehelper vorhanden sind, die eine dieser Versionen zurückgeben .
Nkosi
2
Ihre Antwort ist noch gültig. Fühlen Sie sich also nicht entmutigt. Ich habe nur auf einige Ressourcen hingewiesen, die Sie zur Unterstützung Ihrer Antwort verwenden können.
Nkosi
1
Ja, das stimmt.
Hamed Naeemaei
9

Hier ist ein vereinfachtes Beispiel für das Streaming einer Datei:

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

Hinweis:

Verwenden Sie unbedingt FileStreamResultvon Microsoft.AspNetCore.Mvcund nicht von System.Web.Mvc.

Gpresland
quelle