ASP.NET Core MVC returning file using FileResult

This blog explains how you can return files to client from ASP.NET Core application using fileresult actionresults like FileContentResult, FileStreamResult, VirtualFileResult, PhysicalFileResult.

FileResult is an abstract base class for all file rendering action result, user can render file in the browser or download the required file using these built-in action results. By following this blog you will create a small application to understand FileResults by using all these FileResults.

  1. Create ASP.NET Core MVC application

    Open your visual studio and create an ASP.NET Core MVC application. You can follow getting started with ASP.NET Core MVC and .net5, this creates a simple application with Employee Area and related controller, action methods.

    Add a download area to your application by right click Areas -> Add -> Area -> MVC Area -> give name as download. This creates a folder with name download and subfolders for controllers, views, models. The Area is created to logically group download related functionality of the application.

  2. Create ASP.NET Core MVC Controller

    MVC controller is the initial entry point of any MVC application, this controls users' actions by executing Action methods and returning action results. for more details on the MVC controller visit the ASP.NET Core MVC controller Action method and action result.

    In this step, you will add EmployeeReports controller in download area. Right click on Areas -> Download -> Controllers folder and select Add -> Controllers -> MVC Controller Empty -> name it as EmployeeReportsController and click Ok.

    Add the Area and Route attributes as shown in the below code to EmployeeReports controller class. To get more details about Area - How to use ASP.NET Core MVC Area.

    namespace MVC5Tutorial.Areas.Download.Controllers
    {
        [Area("download")]
        [Route("/EmployeeReports")]
        public class EmployeeReportsController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
        }
    }
    

    Create a folder under wwwroot folder with name download to keep downloadable files. Add a sample file to this folder. Your file structure should be like this.

    ASP.NET Core MVC FileResult Example

  3. FileResult

    The action result that returns FileResults writes files as a response. The File method takes two parameters first is the path of the file and the second is the MIME type.

    The following code renders a pdf file to the browser. The File method uses the file path and the MIME type that is application/pdf. Add this code to the EmployeeReportsController file.

    [Route("/EmployeeReports/GetLearningReport")]
    public FileResult GetLearningReport()
    {   
        string path = "/download/workplace-learning-report-2021.pdf";
        return File(path, "application/pdf");
    }
    

    Navigate to https://localhost:<port number>/EmployeeReports/GetLearningReport. PDF file returned to browser.

    ASP.NET Core MVC return file result

  4. FileContentResult

    The FileContentResult inherits from FileResult. That converts file content to byte array and returns it as a file to the browser, it does not send the file directly to the browser.

    To convert file content to byte array you can use the ReadAllBytes function of the System.IO.File object. Following code converts pdf content to byte array and returns a file.

    FileContentResult is mostly used when your file contents are stored in the database with byte array / varbinary datatype column.

    [Route("/EmployeeReports/GetFileContentResult")]
    public FileContentResult GetFileContentResult()
    {
        string path = "wwwroot/download/workplace-learning-report-2021.pdf";           
        byte[] fileContent = System.IO.File.ReadAllBytes(path); 
        return new FileContentResult(fileContent, "application/pdf");
    }
    

    You can also use ReadAllBytesAsync to convert file content to a byte array and generate the file asynchronously. Here action method returns Task<FileContentResult>

    [Route("/EmployeeReports/GetFileContentResultAsync")]
    public async Task<FileContentResult> GetFileContentResultAsync()
    {
        string path = "wwwroot/download/workplace-learning-report-2021.pdf";
        byte[] data = await System.IO.File.ReadAllBytesAsync(path);
        return new FileContentResult(data, "application/pdf");
    }
                
  5. FileStreamResult

    The FileStreamResult sends binary content to the response by using a stream instance when we want to return the file as a FileStream. The contents are streamed while returning to the client. The streamed response appears on the browser as a downloaded file.

    FileStreamResult is very useful for playing video or dynamically create a zip file and download it.

    Implement following code in EmployeeReportsController and navigate to http://localhost:<port number>/EmployeeReports/GetFileStreamResult. The file with the name employee-report.pdf will be downloaded to the download folder of the browser.

    [Route("/EmployeeReports/GetFileStreamResult")]
    public FileStreamResult GetFileStreamResult()
    {
        string path = "wwwroot/download/workplace-learning-report-2021.pdf";
        var stream = new MemoryStream(System.IO.File.ReadAllBytes(path));
        return new FileStreamResult(stream, new MediaTypeHeaderValue("application/pdf"))
        {
            FileDownloadName = "employee-report.pdf"
        };
    }
                
  6. VirtualFileResult

    The VirtualFileResult can be used to return files that reside under /wwwroot folder of the ASP.NET MVC application.

    [Route("/EmployeeReports/GetVirtualFileResult")]
    public VirtualFileResult GetVirtualFileResult()
    {
        string path = "download/workplace-learning-report-2021.pdf";
        return new VirtualFileResult(path, "application/pdf");
    }
    
  7. PhysicalFileResult

    Sometimes you need to return the file from a physical location, not from relative to wwwroot folder. You will have to _hostingEnvironment.ContentRootPath to access the physical path.

    Inject Dependency of IWebHostEnvironment through the constructor.

    public class EmployeeReportsController : Controller
    {
        private readonly IWebHostEnvironment _hostingEnvironment;
    
        public EmployeeReportsController(IWebHostEnvironment hostingEnvironment)
        {
            this._hostingEnvironment = hostingEnvironment;
        }
    }
    

    The following code returns a pdf file from the physical location.

    [Route("/EmployeeReports/GetPhysicalFileResult")]
    public PhysicalFileResult GetPhysicalFileResult()
    {
        string path = "/wwwroot/download/workplace-learning-report-2021.pdf";
        return new PhysicalFileResult(_hostingEnvironment.ContentRootPath 
            + path, "application/pdf");
    }
    
  8. MIME type from Filename Extension

    If the MIME type is not known at design time as multiple types of files will be returned by action method then you can use FileExtensionContentTypeProvider from Microsoft.AspNetCore.StaticFiles namespace.

    private string GetMIMEType(string fileName)
    {
        var provider = 
            new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
        string contentType;
        if (!provider.TryGetContentType(fileName, out contentType))
        {
            contentType = "application/octet-stream";
        }
        return contentType;
    }
    
    [Route("/EmployeeReports/GetLearningReport")]
    public FileResult GetLearningReport()
    {
        string fileName = "workplace-learning-report-2021.pdf";
        string path = "/download/workplace-learning-report-2021.pdf";
        return File(path, GetMIMEType(fileName));
    }
    
                
  9. Return files from database

    You might have stored your files in the database in varbinary datatype columns instead of saving them on physical disks. You can use FileContentResult to return files by converting database stored bytearray to FileContent.

    The following code reads the file content of image from AdventureWorks2017 database. You can create this database in SQL server and connect to SQL Server database from .net core application.

    [Route("/EmployeeReports/GetProductPhoto/{productid}")]
    public ActionResult GetProductPhoto(int productID)
    {
    byte[] fileContent;
    string contentType = string.Empty;
    string fileName = string.Empty;
    
    using (SqlConnection con =
        new SqlConnection("<connection string >")) 
    {
        using(SqlCommand cmd = new SqlCommand())
        {
            cmd.Connection= con;
            cmd.CommandType = System.Data.CommandType.Text;
            cmd.CommandText = "SELECT [LargePhoto], [LargePhotoFileName]  FROM " +
                " [AdventureWorks2017].[Production].[ProductPhoto]" + 
                $" WHERE ProductPhotoID = { productID }";
    
            con.Open();
            using (SqlDataReader sdr = cmd.ExecuteReader())
            {
                sdr.Read();
                fileContent = (byte[])sdr["LargePhoto"];
                contentType = GetMIMEType(sdr["LargePhotoFileName"].ToString());
                fileName = sdr["LargePhotoFileName"].ToString();
            }
            con.Close();
        }
    }
                
    return new FileContentResult(fileContent, contentType);
    }
                

    Navigate to http://localhost:<port number>/EmployeeReports/GetProductPhoto/77. This should render a image file to browser from database as shown in this picture.

    ASP.NET Core MVC FileResult from database

Source code on Git hub Source Code on Github

Speak your mind
Please login to post your comment!