Restituisce il file nell'API Web ASP.Net Core


131

Problema

Voglio restituire un file nel mio controller API Web ASP.Net, ma tutti i miei approcci restituiscono HttpResponseMessagecome JSON.

Codice finora

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

Quando chiamo questo endpoint nel mio browser, l'API Web restituisce HttpResponseMessagecome JSON con l'intestazione del contenuto HTTP impostata su application/json.

Risposte:


228

Se questo è ASP.net-Core, stai mescolando le versioni delle API web. Chiedi all'azione di restituire un derivato IActionResultperché nel tuo codice attuale il framework HttpResponseMessageconsidera un modello.

[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
Nel mio caso avevo bisogno di renderizzare un Excel in memoria e restituirlo per il download, quindi dovevo anche definire un nome di file con estensione: in return File(stream, "application/octet-stream", "filename.xlsx"); questo modo quando scarica l'utente può aprirlo direttamente.
KMJungersen,

Capisco cosa alla NotFound()fine fa, ma risiede in .NET Core o è qualcosa di locale per il tuo progetto?
ΩmegaMan

2
@ ΩmegaMan è un metodo di supporto attivo ControllerBasee fa parte del framework stesso docs.microsoft.com/en-us/dotnet/api/…
Nkosi

3
Ok, ho riscontrato il mio problema, sebbene il mio controller funzionasse in .NET Core 2.2, non era derivato dalla classe base e Controllerquindi non aveva accesso al ControllerBase.NotFound()metodo. Una volta derivato, ha funzionato tutto. lol / thx
ΩmegaMan

1
Questo metodo consuma memoria di sistema nel caso in cui si scarichino file di grandi dimensioni dal server? La mia prima ipotesi non lo è, dato il fatto che non stiamo creando un nuovo MemoryStream (). Gradirei una risposta. grazie
Ehsan Najafi il

16

È possibile restituire FileResult con questi metodi:

1: restituisce 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: restituisce 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
Se all'interno di a ControllerBaseci sono molte versioni sovraccariche di ControllerBase.Filehelper che restituisce una di quelle.
Nkosi,

2
La tua risposta è ancora valida Quindi non sentirti scoraggiato. Stavo solo sottolineando alcune risorse che puoi usare per supportare la tua risposta.
Nkosi,

1
Si è vero.
Hamed Naeemaei,

9

Ecco un esempio semplicistico di streaming di un 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");
}

Nota:

Assicurati di usare FileStreamResultda Microsoft.AspNetCore.Mvce non da System.Web.Mvc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.