Renvoyer le fichier dans l'API Web ASP.Net Core

132

Problème

Je souhaite renvoyer un fichier dans mon contrôleur d'API Web ASP.Net, mais toutes mes approches renvoient le HttpResponseMessagesous forme de JSON.

Code jusqu'à présent

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

Lorsque j'appelle ce point de terminaison dans mon navigateur, l'API Web renvoie le en HttpResponseMessagetant que JSON avec l'en-tête de contenu HTTP défini sur application/json.

Jan Kruse
la source

Réponses:

230

S'il s'agit d'ASP.net-Core, vous mélangez des versions d'API Web. Demandez à l'action de renvoyer un dérivé IActionResultcar dans votre code actuel, le framework est traité HttpResponseMessagecomme un modèle.

[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
la source
12
Dans mon cas, j'avais besoin de restituer un Excel en mémoire et de le renvoyer pour téléchargement, donc j'avais également besoin de définir un nom de fichier avec une extension: De return File(stream, "application/octet-stream", "filename.xlsx"); cette façon, lors du téléchargement, l'utilisateur peut l'ouvrir directement.
KMJungersen
Je comprends ce que fait NotFound()finalement, mais réside-t-il dans .NET Core ou s'agit-il d'un élément local de votre projet?
ΩmegaMan
2
@ ΩmegaMan c'est une méthode d'aide sur ControllerBaseet fait partie du cadre lui-même docs.microsoft.com/en-us/dotnet/api/…
Nkosi
3
Ok, j'ai trouvé mon problème, bien que mon contrôleur fonctionnait dans .NET Core 2.2, il n'était pas dérivé de la classe de base Controlleret n'avait donc pas accès à la ControllerBase.NotFound()méthode. Une fois dérivé, tout a fonctionné. lol / thx
ΩmegaMan
1
Cette méthode consomme-t-elle de la mémoire système au cas où vous téléchargez des fichiers volumineux à partir du serveur? Ma première hypothèse n'est pas, étant donné que nous ne créons pas un nouveau MemoryStream (). J'apprécierais une réponse. thx
Ehsan Najafi
18

Vous pouvez retourner FileResult avec ces méthodes:

1: Renvoyer 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: Renvoyer 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
la source
2
Si dans un ControllerBaseil existe de nombreuses versions surchargées de ControllerBase.Filehelper qui renvoie l'une d'entre elles.
Nkosi
2
Votre réponse est toujours valable. Alors ne vous sentez pas découragé. Je voulais juste signaler quelques ressources que vous pouvez utiliser pour étayer votre réponse.
Nkosi
1
Oui c'est vrai.
Hamed Naeemaei le
10

Voici un exemple simpliste de streaming d'un fichier:

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

Remarque:

Assurez-vous d'utiliser FileStreamResultde Microsoft.AspNetCore.Mvcet non de System.Web.Mvc.

gprresland
la source