How to receive a file in a web API request in ASP.NET Core

By FoxLearn 3/1/2025 2:57:53 AM   138
When a client uploads a file in a multipart/form-data request, it is captured in an IFormFile object. This object contains metadata about the file, such as the file's name, and exposes the file's content as a stream, enabling you to either save or process the file as needed.

To access the IFormFile object, you can use Request.Form.Files:

For example, Retrieve the file directly from the request

[Route("[controller]")]
[ApiController]
public class FilesController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> Post()
    {
        IFormFile file = Request.Form.Files.FirstOrDefault();

        // Process the file content

        return Ok($"Received file {file.FileName} with size in bytes {file.Length}");
    }
}

Alternatively, you can add an IFormFile parameter directly to your action method, and ASP.NET Core will map the file based on the form field name:

For example, Using an IFormFile parameter in the method signature

[Route("[controller]")]
[ApiController]
public class FilesController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> Post(IFormFile file)
    {
        // Process the file content

        return Ok($"Received file {file.FileName} with size in bytes {file.Length}");
    }
}

Make sure that the parameter name in the method (file in this case) matches the name attribute in the form's file input field, or else the mapping will fail, and the IFormFile will be null.

Saving the File to Disk

You can save the file to disk by copying the stream from the IFormFile object into a file stream.

using System.IO;

[HttpPost]
public async Task<IActionResult> Post(IFormFile file)
{
    if (file.Length <= 0)
        return BadRequest("Empty file");

    // Strip out any path specifiers (e.g., /../)
    var originalFileName = Path.GetFileName(file.FileName);

    // Generate a unique file path
    var uniqueFileName = Path.GetRandomFileName();
    var uniqueFilePath = Path.Combine(@"C:\temp\", uniqueFileName);

    // Save the file to disk
    using (var stream = System.IO.File.Create(uniqueFilePath))
    {
        await file.CopyToAsync(stream);
    }

    return Ok($"Saved file {originalFileName} with size {file.Length / 1024m:#.00} KB using unique name {uniqueFileName}");
}

In this case, the file is saved to a predefined directory (C:\temp\), but for production, you should use a configuration setting for the file path.

Using IFormFile as a Model Property

If you need to handle additional data along with the file, you can include an IFormFile in a model class:

public class Document
{
    public string Title { get; set; }
    public string Version { get; set; }
    public IFormFile File { get; set; }
}

Then, bind this model to your method with the [FromForm] attribute:

[HttpPost]
public async Task<IActionResult> Post([FromForm]Document document)
{
    // Process the file

    return Ok($"Processed document {document.Title} v{document.Version} - {document.File.FileName}");
}

Make sure to include [FromForm] when using model binding to avoid a 415 Media Not Supported error.

File Size Limits

By default, Kestrel web server imposes a request size limit of 30 MB, and the size of each section in a multipart request is limited to 128 MB. You can customize these limits, either globally or per action.

[HttpPost]
[RequestSizeLimit(60000000)]  // Set size limit to 60 MB
public async Task<IActionResult> Post(IFormFile file)
{
    // Process file

    return Ok();
}

If the client exceeds the form size limit or request size limit, it will result in an error.

Receiving Multiple Files

You can handle multiple file uploads in two ways:

  1. For a fixed number of files, define multiple IFormFile parameters.
  2. For an arbitrary number of files, use IEnumerable<IFormFile> to receive multiple files in a single parameter.

For example, receive multiple files

[HttpPost]
public async Task<IActionResult> Post(IEnumerable<IFormFile> files)
{
    foreach (var file in files)
    {
        // Process each file
    }

    return Ok();
}

When using IEnumerable<IFormFile>, ensure the client names the file fields consistently in the form data.