Returning Files from Controllers

In ASP.NET Core MVC, controllers are not limited to returning views or HTML content. They can also return files such as PDFs, images, and Excel documents directly to the browser.

This feature is commonly used in real-world applications for downloading reports, invoices, documents, and media files.

Understanding how to return files from controllers helps you build more complete and practical MVC applications.


What Does Returning Files Mean?

Returning a file means sending file data from the server to the browser as part of the HTTP response.

Instead of rendering a web page, the browser either:

  • Displays the file (like images or PDFs)
  • Downloads the file

This behavior depends on the file type and response headers.


Basic Example: Returning a File

ASP.NET Core provides the File() method to return files.

public IActionResult DownloadFile()
{
    var bytes = System.IO.File.ReadAllBytes("sample.pdf");

    return File(bytes, "application/pdf", "sample.pdf");
}

Explanation:

  • ReadAllBytes() reads the file from disk
  • File() sends the file to the browser
  • The MIME type defines the file type
  • The last parameter sets the download file name

Returning PDF Files

PDF files are widely used in applications such as invoices, reports, and documents.

public IActionResult DownloadPdf()
{
    var filePath = "files/report.pdf";

    var bytes = System.IO.File.ReadAllBytes(filePath);

    return File(bytes, "application/pdf", "report.pdf");
}

Real-world use cases:

  • Invoice download
  • Report generation
  • Document sharing

Returning Files from Controllers in ASP.NET Core MVC (Complete Flow)

In real-world ASP.NET Core MVC applications, file downloads are triggered from the UI. A user clicks a button or link, a controller action executes, and a file is returned as a response.

In this section, we will understand the complete flow including controller, action method, and the view that triggers the file download.

Scenario: Download Invoice PDF

A user clicks a button on the UI to download an invoice. The request goes to the controller, and the controller returns a PDF file.

Step 1: Controller and Action Method

This controller contains an action method that reads a file and returns it to the browser.

using Microsoft.AspNetCore.Mvc;

namespace MyMvcApp.Controllers
{
    public class InvoiceController : Controller
    {
        // Action method to download invoice
        public IActionResult DownloadInvoice(int orderId)
        {
            // Build file path dynamically
            var filePath = "wwwroot/invoices/invoice_" + orderId + ".pdf";

            // Read file from server
            var bytes = System.IO.File.ReadAllBytes(filePath);

            // Return file to browser
            return File(
                bytes,
                "application/pdf",
                "Invoice.pdf"
            );
        }
    }
}

What this does:

  • Takes orderId from request
  • Finds the corresponding invoice file
  • Returns it as a downloadable PDF

Step 2: View (UI) to Trigger Download

This is the page where the user clicks a button to download the invoice.

File: Views/Invoice/Index.cshtml

<h2>My Orders</h2>

<button onclick="downloadInvoice(101)">Download Invoice</button>

Step 3: Call Controller Action

Using Tag Helpers (Best Practice) Call Controller Action

In Razor, you should prefer Tag Helpers:

<a asp-controller="Invoice" 
   asp-action="DownloadInvoice" 
   asp-route-orderId="101">
   Download Invoice
</a>

This is cleaner, maintainable, and avoids hardcoded URLs.


JavaScript function to Call Controller Action

function downloadInvoice(orderId) {

    let url = "/Invoice/DownloadInvoice?orderId=" + orderId;

    // Redirect to controller action
    window.location = url;
}

Step 4: Complete Flow

  1. User clicks Download Invoice button
  2. JavaScript builds URL with orderId
  3. Request goes to InvoiceController
  4. Action method reads file
  5. File is returned as response
  6. Browser downloads the PDF

Alternative: Using Anchor Tag (No JavaScript)

You can also trigger download using a simple link:

<a href="/Invoice/DownloadInvoice?orderId=101">Download Invoice</a>

This works the same way and is often preferred for simplicity.


What the User Sees

  • If file name is provided → File downloads
  • If file name is NOT provided → Browser may display file

For PDFs:

  • May open in browser OR download (based on settings)

Important Points

  • Controller does not return a View here
  • It directly returns a FileResult
  • Browser decides how to handle the file
  • Query string (orderId) is used to identify file

Returning Image Files

Images can be displayed directly in the browser without downloading.

public IActionResult GetImage()
{
    var bytes = System.IO.File.ReadAllBytes("images/photo.jpg");

    return File(bytes, "image/jpeg");
}

Explanation:

  • No file name is provided
  • The browser displays the image instead of downloading it

Displaying File Instead of Downloading

So far, we have seen how files are downloaded. But in many cases, you may want to display the file directly in the browser instead of forcing a download.

This is commonly used for images, PDFs, and media files.

Controller Example

If you do NOT provide a file name in the File() method, the browser will try to display the file.

public IActionResult ViewInvoice(int orderId)
{
    var filePath = "wwwroot/invoices/invoice_" + orderId + ".pdf";

    var bytes = System.IO.File.ReadAllBytes(filePath);

    return File(
        bytes,
        "application/pdf"
    );
}

Razor View (UI)

Now, instead of downloading, we can open the file in a new tab.

<a asp-controller="Invoice" 
   asp-action="ViewInvoice" 
   asp-route-orderId="101" 
   target="_blank">
   View Invoice
</a>

What Happens Here

  • No file name is provided → browser does NOT force download
  • Content-Type is application/pdf
  • Browser opens the file in a new tab

When to Use This Approach

  • Preview documents before download
  • Display images or PDFs
  • Show reports inside browser

Note: The behavior depends on the browser. Some browsers may still download the file based on settings, but most modern browsers display PDFs and images inline.


Returning Excel Files

Excel files are commonly used for exporting data in applications.

public IActionResult DownloadExcel()
{
    var bytes = System.IO.File.ReadAllBytes("files/data.xlsx");

    return File(
        bytes,
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "data.xlsx");
}

Real-world use cases:

  • Exporting reports
  • Admin dashboards
  • User data downloads

Using FileStream for Large Files

For large files, using streams is more efficient than loading everything into memory.

public IActionResult DownloadLargeFile()
{
    var stream = new FileStream("files/large.pdf", FileMode.Open);

    return File(stream, "application/pdf", "large.pdf");
}

Why use streams?

  • Better performance
  • Lower memory usage
  • Ideal for large files

Real-World Example: Invoice Download

In an e-commerce application, users often download invoices.

public IActionResult DownloadInvoice(int orderId)
{
    var filePath = "invoices/invoice_" + orderId + ".pdf";

    var bytes = System.IO.File.ReadAllBytes(filePath);

    return File(bytes, "application/pdf", "invoice.pdf");
}

Best Practices

  • Always use correct MIME types
  • Validate file paths to avoid security risks
  • Use streams for large files
  • Avoid exposing sensitive files

Summary

Returning files from controllers is a key feature in ASP.NET Core MVC. It allows applications to provide downloads, display media, and generate reports.

Once you understand how file responses work, you can build real-world features like invoice downloads, report exports, and document management systems.

In upcoming lessons, we will move into Models and understand how data flows into MVC applications.