Возвращаемый файл в ASP.Net Core Web API

проблема

Я хочу вернуть файл в мой ASP.Net Web API Controller, но все мои подходы возвращают 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;
}

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

7 ответов

Решение

Если это 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();

        return File(stream, "application/octet-stream"); // returns a FileStreamResult
    }    
}

Вы можете вернуть 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
        };
    }

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

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

Заметка:

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

Веб-API ASP.NET 5 и Angular 12

Вы можете вернуть объект FileContentResult (Blob) с сервера. Он не будет загружен автоматически. Вы можете программно создать тег привязки в своем интерфейсном приложении и установить для свойства href URL-адрес объекта, созданный из Blob, описанным ниже способом. Теперь нажатие на якорь загрузит файл. Вы можете установить имя файла, установив также атрибут «загрузка» для привязки.

      downloadFile(path: string): Observable<any> {
        return this._httpClient.post(`${environment.ApiRoot}/accountVerification/downloadFile`, { path: path }, {
            observe: 'response',
            responseType: 'blob'
        });
    }

saveFile(path: string, fileName: string): void {
            this._accountApprovalsService.downloadFile(path).pipe(
                take(1)
            ).subscribe((resp) => {
                let downloadLink = document.createElement('a');
                downloadLink.href = window.URL.createObjectURL(resp.body);
                downloadLink.setAttribute('download', fileName);
                document.body.appendChild(downloadLink);
                downloadLink.click();
                downloadLink.remove();
            });
            
        }

Бэкэнд

      [HttpPost]
[Authorize(Roles = "SystemAdmin, SystemUser")]
public async Task<IActionResult> DownloadFile(FilePath model)
{
    if (ModelState.IsValid)
    {
        try
        {
            var fileName = System.IO.Path.GetFileName(model.Path);
            var content = await System.IO.File.ReadAllBytesAsync(model.Path);
            new FileExtensionContentTypeProvider()
                .TryGetContentType(fileName, out string contentType);
            return File(content, contentType, fileName);
        }
        catch
        {
            return BadRequest();
        }
    }

    return BadRequest();

}

FileStreamResult у меня работает. и File не является IActionResult. Я не знаю, как это может работать.

Ниже приведен базовый пример возврата файла (например, файла изображения) в .NET Core Web API:

      <img src="@Url.Action("RenderImage", new { id = id})" alt="No Image found" />

Ниже приведен код для возврата файла из контроллера для просмотра. Ниже приведен метод действия, который вернет файл:

          [Route("api/[controller]")]
    public class DownloadController : Controller
    {
        //GET api/download/123
        [HttpGet]
        public async Task<IActionResult> RenderImage(string userId)
        {
            //get Image file using _fileservice from db
            var result = await _fileService.getFile(userId);

            if (result.byteStream == null)
                return NotFound();

            return File(result.byteStream, result.ContentType, result.FileName);
        }
    }

Примечание:

Наш файл должен быть сначала преобразован в byte[], а затем сохранен в базе данных как varbinary(max) для извлечения.

добавить builder.Services.AddSingleton(); в Program.cs

          [HttpGet("{fileId}")]
    public ActionResult GetFile(string fileId)
    {
        string pathToFile = "test.rar";
        if (!System.IO.File.Exists(pathToFile))
        {
            return NotFound();
        }

        if(!_fileExtensionContentTypeProvider.TryGetContentType(pathToFile,
            out var ContentType))
        {
            ContentType = "application/octet-stream";
        }
        var byets=System.IO.File.ReadAllBytes(pathToFile);
        return File(byets, ContentType, Path.GetFileName(pathToFile));
    }
}
Другие вопросы по тегам