Файл возврата в веб-API ASP.Net Core


132

проблема

Я хочу вернуть файл в свой контроллер веб-API ASP.Net, но все мои подходы возвращают его HttpResponseMessageкак JSON.

Код на данный момент

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

Когда я вызываю эту конечную точку в своем браузере, веб-API возвращает HttpResponseMessageфайл в формате JSON с HTTP-заголовком содержимого, установленным на application/json.

Ответы:


230

Если это ASP.net-Core, значит, вы смешиваете версии веб-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
Хорошо, обнаружил свою проблему, хотя мой контроллер работал в .NET Core 2.2, он не был производным от базового класса Controllerи поэтому не имел доступа к ControllerBase.NotFound()методу. После получения все заработало. lol / thx
ΩmegaMan

1
Использует ли этот метод системную память, если вы загружаете большие файлы с сервера? Мое первое предположение - нет, учитывая тот факт, что мы не создаем новый MemoryStream (). Буду признателен за ответ. спасибо
Ehsan

18

Вы можете вернуть 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
Если в a ControllerBaseесть много перегруженных версий ControllerBase.Fileпомощника, который возвращает любую из них.
Nkosi

2
Ваш ответ все еще в силе. Так что не расстраивайтесь. Я просто указал на некоторые ресурсы, которые вы можете использовать для подтверждения своего ответа.
Nkosi

1
Да, это правда.
Hamed Naeemaei,

10

Вот упрощенный пример потоковой передачи файла:

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

Примечание:

Обязательно используйте FileStreamResultfrom, Microsoft.AspNetCore.Mvcа не from System.Web.Mvc.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.