Coder Perfect

In the ASP.NET Core Web API, return the file.

Problem

In my ASP.Net Web API Controller, I want to return a file, however all of my ways return the HttpResponseMessage as 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;
}

The Web API returns the HttpResponseMessage as JSON with the HTTP Content Header set to application/json when I call this endpoint in my browser.

Asked by Jan Kruse

Solution #1

You’re mixing web API versions if this is ASP.net-Core. Because the framework is treating HttpResponseMessage as a model in your current code, have the action return a derived IActionResult.

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

Note:

Answered by Nkosi

Solution #2

With these methods, you can get a FileResult:

    [HttpGet("get-file-stream/{id}"]
    public async Task<FileStreamResult> DownloadAsync(string id)
    {
        var fileName="myfileName.txt";
        var mimeType="application/...."; 
        Stream stream = await GetFileStreamById(id);

        return new FileStreamResult(stream, mimeType)
        {
            FileDownloadName = fileName
        };
    }
    [HttpGet("get-file-content/{id}"]
    public async Task<FileContentResult> DownloadAsync(string id)
    {
        var fileName="myfileName.txt";
        var mimeType="application/...."; 
        byte[] fileBytes = await GetFileBytesById(id);

        return new FileContentResult(fileBytes, mimeType)
        {
            FileDownloadName = fileName
        };
    }

Answered by Hamed Naeemaei

Solution #3

Here’s a simple example of how to stream a 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");
}

Note:

Use FileStreamResult from Microsoft.AspNetCore.Mvc instead of System.Web.Mvc if possible.

Answered by gpresland

Solution #4

Angular 12 and ASP.NET 5 WEB API

From the server, you can get a FileContentResult object (Blob). It will not be downloaded automatically. You can use the method below to build an anchor tag in your front-end app and change the href property to an object URL formed from the Blob. The file will now be downloaded by clicking on the anchor. The ‘download’ element on the anchor can also be used to specify a file name.

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

        }

Backend

[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();

}

Answered by Tanvir

Solution #5

In.NET Core Web API, the following is a basic example of returning a file (for example, an Image file):

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

The code for returning File from the controller to the view is shown below. The action method that will return a file is as follows:

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

Note:

Answered by Adeel Ahmed

Post is based on https://stackoverflow.com/questions/42460198/return-file-in-asp-net-core-web-api