Retornar arquivo na API da Web do ASP.Net Core


131

Problema

Desejo retornar um arquivo no meu controlador de API da Web do ASP.Net, mas todas as minhas abordagens retornam HttpResponseMessagecomo JSON.

Código até agora

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 chamo esse terminal no meu navegador, a API da Web retorna HttpResponseMessagecomo JSON com o cabeçalho de conteúdo HTTP definido como application/json.

Respostas:


228

Se esse for o ASP.net-Core, você estará misturando versões da API da web. Faça com que a ação retorne uma derivada, IActionResultporque no seu código atual a estrutura está tratando HttpResponseMessagecomo um modelo.

[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
No meu caso, eu precisava renderizar um Excel na memória e devolvê-lo para download. Por isso, também era necessário definir um nome de arquivo com extensão: return File(stream, "application/octet-stream", "filename.xlsx"); Dessa forma, ao fazer o download, o usuário pode abri-lo diretamente.
precisa saber é o seguinte

Entendo o que NotFound()isso faz, mas ele reside no .NET Core ou é algo local no seu projeto?
ΩmegaMan

2
@ EgamegaMan, é um método auxiliar ControllerBasee faz parte da própria estrutura docs.microsoft.com/en-us/dotnet/api/…
Nkosi

3
Ok, encontrei meu problema, embora meu controlador estivesse trabalhando no .NET Core 2.2, ele não era derivado da classe base Controllere, portanto, não tinha acesso ao ControllerBase.NotFound()método. Uma vez derivado, tudo funcionou. lol / thx
ΩmegaMan

1
Este método consome memória do sistema no caso de você estar baixando arquivos grandes do servidor? Meu primeiro palpite não é, dado que não estamos criando um novo MemoryStream (). Eu apreciaria uma resposta. thx
Ehsan Najafi

16

Você pode retornar o FileResult com estes métodos:

1: Retornar 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: Return 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 dentro de um, ControllerBaseexistem muitas versões sobrecarregadas do ControllerBase.Filehelper que retornam qualquer uma delas.
Nkosi

2
Sua resposta ainda é válida. Portanto, não se sinta desanimado. Eu estava apenas apontando alguns recursos que você pode usar para apoiar sua resposta.
Nkosi

1
Sim isso é verdade.
Hamed Naeemaei

9

Aqui está um exemplo simplista de streaming de um arquivo:

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:

Certifique-se de usar FileStreamResultde Microsoft.AspNetCore.Mvce não de System.Web.Mvc.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.