Our users will inevitably want to share more than text-based information with us. They may wish to transmit images, videos, or third-party formats to our applications. Uploading files is a long-solved problem, and in this post, we’ll see how we can enable file uploads for your ASP.NET applications. This approach works interchangeably between ASP.NET MVC or Razor Pages, but for the sake of brevity, we will be working with Razor pages.

HTML Markup

ASP.NET is a web platform and embraces the mechanisms of the web. In this post, we will be using the form, input, and button HTML tags to build the purest file upload experience we can. Here is the markup for a Razor page.

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">
        The filename is <br/>
        @Model.FileName
    </h1>
    
    <form method="post" action="" enctype="multipart/form-data">
        <input name="file" type="file" />
        <button type="submit">Upload</button>
    </form>
    
</div>

Important elements to note about our form:

The form’s enctype is multipart/form-data. The input’s type is file, which uses the native browsers file selection control. The button submits the form.

The use of multipart/form-data tells the browser to create a unique request to the server, with each input isolated to its boundary. The boundary definitions allow the server to parse the requested switching between different content types. In the example below, we have a text input and a file input.

POST /test HTTP/1.1 
Host: foo.example
Content-Type: multipart/form-data;boundary="boundary" 

--boundary 
Content-Disposition: form-data; name="field1" 

value1 
--boundary 
Content-Disposition: form-data; name="field2"; filename="example.txt" 

value2
--boundary--

IFormFile

ASP.NET Core has introduced an IFormFile interface that represents transmitted files in an HTTP request. The interface gives us access to metadata like ContentDisposition, ContentType, FileName and more. The IFormFile interface also allows us to read the contents of a file via an accessible Stream.

Note: Buffering occurs for all transmitted files, which users can exploit to perform a denial of service attack. We should take precautions against such attack vectors.

To use the IFormFile in our application, we need only add a parameter to our POST handler. In this case, we are using Razor pages. We are careful to name the method parameter the same as our HTML input’s name.

public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;
    public string FileName { get; set; }

    public IndexModel(ILogger<IndexModel> logger)
    {
        _logger = logger;
        FileName = "Not Available";
    }

    public void OnGet()
    {
    }

    public void OnPost(IFormFile file)
    {
        FileName = file.FileName;
    }
}

ASP.NET model binding mechanisms will take care of the rest for us. Here is the result of a single file upload.

single file upload

Upload Multiple Files

ASP.NET can also handle multiple file uploads with a few minor tweaks to our sample. In our view, we need to name each input the same so that they get bound to the same collection.

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">
        The filename is <br/>
        <ul>
        @foreach (var name in Model.FileName)
        {
            <li>@name</li>
        }
        </ul>
    </h1>
    
    <form method="post" action="" enctype="multipart/form-data">
        <input name="file" type="file" />
        <input name="file" type="file" />
        <input name="file" type="file" />
        <button type="submit">Upload</button>
    </form>
    
</div>

And we also need to change our ASP.NET handler.

public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;
    public string[] FileName { get; set; }

    public IndexModel(ILogger<IndexModel> logger)
    {
        _logger = logger;
        FileName = new[] {"Not Available"};
    }

    public void OnGet()
    {
    }

    public void OnPost(IFormFile[] file)
    {
        FileName = file
            .Select(x => x.FileName)
            .ToArray();
    }
}

Let’s look at the result of multiple file uploads.

multiple file uploads

Conclusion

File uploads are a little less scary with the introduction of IFormFile and an understanding of web standards. There are a few limitations and pitfalls explained in greater detail on the Microsoft documentation site. I hope you found this post helpful, and please leave a comment below.