How to Handle File Uploads with ASP.NET Core

ionx

Ionx Solutions

Posted on May 7, 2024

How to Handle File Uploads with ASP.NET Core

Managing file uploads from end users is often required in web apps and APIs. This tutorial will guide you through the process of handling uploaded files using using ASP.NET Core and C#.

NOTE: To follow this tutorial, you will need the following:

To allow files to be uploaded, you will:

  1. Create ASP.NET Core Razor views that allow the user to select a file to upload
  2. Create ASP.NET Core controllers to work with uploaded files

Of course, you will also want to do something with each uploaded file! In this tutorial, we're going to write C# code to show information about the file, and also to scan it for malware using Verisys Antivirus API.

Verisys Antivirus API is a language-agnostic REST API that allows you to easily add malware scanning to mobile apps, web apps and backend processing.

By scanning user-generated content and file uploads, Verisys Antivirus API can stop dangerous malware at the edge, before it reaches your servers, applications - or end users.

Project Setup

First, we need to create a new ASP.NET Core MVC project.

  • Start Visual Studio and select File > New > Project

  • Select the template named ASP.NET Core Web App (Model-View-Controller) and click Next

Visual Studio project template selection

  • Enter Web for the Project Name, choose a location to save the project, then click Next

Visual Studio project name

  • For the Framework, select .NET 8.0 (Long Term Support), then click Create

Visual Studio project SDK

  • The new project will be created, and you should see this folder structure in Visual Studio's Solution Explorer:

Folder structure visible in Solution Explorer

Running the App

Now we've created a new project, let's make sure it runs!

  • Press CTRL+F5, or click the Start Without Debugging button:

Start without debugging

  • The first time you run the project, you will be asked to install an SSL/TLS certificate - click Yes on both popups:

Installation of SSL/TLS certificate

Installation of SSL/TLS certificate

  • Visual Studio will then run the app, opening it in the default browser:

ASP.NET Core web app running in a browser

  • While running your project, Visual Studio will open a terminal as well as the browser - this is for the default web server, Kestrel. If you press CTRL-C, it will shut down the web server and stop running your project.

Start without debugging

File Upload

To enable file uploads, we need to add:

  1. View models, to encapsulate information about uploaded files
  2. A view with a form that allows users to select and upload a file
  3. A view to show information about the uploaded file
  4. A controller, to show the views and handle the uploaded file
  5. We'll also update the main layout view, just to add links to our new pages

Let's get started!

  • First, create file Models/FileModels.cs, with content:
namespace Web.Models;

public record UploadModel(IFormFile File);
public record ResultModel(string Name, long Size, string MimeType, 
    MalwareStatus MalwareStatus, string[] Signals);

public record ApiResultModel(Guid Id, MalwareStatus Status, string[] Signals);
public enum MalwareStatus { Unknown, Clean, Threat }
Enter fullscreen mode Exit fullscreen mode
  • Next, create a folder Views/Upload, and inside a view file Views/Upload/Index.cshtml with content:
@model UploadModel
@{
    ViewData["Title"] = "Upload File";
}

<form method="post" enctype="multipart/form-data">
    <input type="file" asp-for="File">
    <button type="submit">Upload File</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Note the form's encoding type (enctype) property is set to multipart/form-data - this is required for uploading files.

  • Next, create view file Views/Upload/Result.cshtml with content:
@model ResultModel
@{
    ViewData["Title"] = "Result";
}

<h1>Result</h1>

<div>File Name: @Model.Name</div>
<div>File Size: @Model.Size</div>
<div>Mime Type: @Model.MimeType</div>
<div>Malware Status: @Model.MalwareStatus</div>
Enter fullscreen mode Exit fullscreen mode
  • Create a controller file Controllers/UploadController.cs with content:
using Microsoft.AspNetCore.Mvc;
using Web.Models;

namespace Web.Controllers;

public class UploadController : Controller
{
    [HttpGet]
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Index(UploadModel model)
    {
        var result = new ResultModel(model.File.FileName, model.File.Length, model.File.ContentType, MalwareStatus.Unknown, []);
        return View("Result", result);
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Finally, update the content of Views/Shared/_Layout.cshtml to add links to our new pages:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>@ViewData["Title"]</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand border-bottom mb-3">
            <div class="container-fluid">
                <div class="navbar-collapse">
                    <a class="nav-link text-dark" href="/upload">Upload File</a>
                    <a class="nav-link text-dark" href="/scan">Scan File</a>
                </div>
            </div>
        </nav>
    </header>

    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

It really is that simple!

Testing File Uploads

Now we’re ready to test file uploads! 🎉

  • Begin by running the project again, either by pressing CTRL+F5, or by click the Start Without Debugging button

  • Your browser should open automatically, showing a page that looks like this:

ASP.NET Core web app running in a browser

  • Click the link Upload File, and you should see one of the new views we created:

Upload file form

  • Press Choose File to select a file to upload, then and press the Upload File button

  • If everything was set up correctly, you should see information about the file being shown in a web page:

Successful file upload

Note that the Malware Status is shown as Unknown - we'll fix that in the next section.

Malware Scanning

Now we're going to use Verisys Antivirus API to scan uploaded files for malware. Following a similar pattern as for the previous section, we need to add:

  1. Registration of an HTTP client with the Dependency Injection (DI) container
  2. A view with a form that allows users to select and upload a file for scanning
  3. A view to show the results of the malware scan
  4. A controller, to show the views and send the uploaded file to Verisys Antivirus API

Let's get started!

  • In file Program.cs, replace line builder.Services.AddControllersWithViews(); with:
// Register an HTTP client for use with Verisys Antivirus API
builder.Services.AddHttpClient<HomeController>(x =>
{
    x.BaseAddress = new Uri("https://eu1.api.av.ionxsolutions.com/v1/");
    x.DefaultRequestHeaders.Add("Accept", "application/json");
    x.DefaultRequestHeaders.Add("X-API-Key", "<YOUR API KEY HERE>");
});

builder.Services.AddControllersWithViews().AddJsonOptions(x => {
    x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
    x.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
});
Enter fullscreen mode Exit fullscreen mode

NOTE:
The X-API-Key in the above code will need to be replaced with a real API key to scan files for real. Don’t have an API key? Subscribe now!

  • Create a folder Views/Scan, and inside a view file Views/Scan/Index.cshtml with content:
@model UploadModel
@{
    ViewData["Title"] = "Scan File";
}

<form method="post" enctype="multipart/form-data">
    <input type="file" asp-for="File">
    <button type="submit">Scan File</button>
</form>
Enter fullscreen mode Exit fullscreen mode
  • Next, create view file Views/Scan/Result.cshtml with content:
@model ResultModel
@{
    ViewData["Title"] = "Result";
}

<h1>Result</h1>

<div>File Name: @Model.Name</div>
<div>File Size: @Model.Size</div>
<div>Mime Type: @Model.MimeType</div>
<div>Malware Status: @Model.MalwareStatus</div>

@if (Model.MalwareStatus == MalwareStatus.Threat)
{
    foreach (var signal in Model.Signals)
    {
        <div>Signal: @signal</div>
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Finally, create a controller file Controllers/ScanController.cs with content:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Text.Json;
using Web.Models;

namespace Web.Controllers;

public class ScanController : Controller
{
    private readonly IHttpClientFactory clientFactory;
    private readonly JsonSerializerOptions jsonOptions;

    public ScanController(IHttpClientFactory clientFactory, IOptions<JsonOptions> jsonOptions)
    {
        this.clientFactory = clientFactory;
        this.jsonOptions = jsonOptions.Value.JsonSerializerOptions;
    }

    [HttpGet]
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Index(UploadModel model)
    {
        using var client = this.clientFactory.CreateClient(nameof(HomeController));

        using var formData = new MultipartFormDataContent();
        formData.Add(new StreamContent(model.File.OpenReadStream()), "file", model.File.FileName);

        using var response = await client.PostAsync("malware/scan/file", formData);
        response.EnsureSuccessStatusCode();

        var apiModel = await response.Content.ReadFromJsonAsync<ApiResultModel>(this.jsonOptions);

        var result = new ResultModel(model.File.FileName, model.File.Length, model.File.ContentType, apiModel!.Status, apiModel.Signals);
        return View("Result", result);
    }
}
Enter fullscreen mode Exit fullscreen mode

Testing Malware Scanning

Now we’re ready to test malware scanning! 🎉

  • Begin by running the project again, either by pressing CTRL+F5, or by click the Start Without Debugging button

  • Your browser should open automatically, showing a page that looks like this:

ASP.NET Core web app running in a browser

  • Click the link Scan File, and you should see one of the new views we created:

Scan file form

  • Press Choose File to select a file to upload, then and press the Upload File button

  • If everything was set up correctly, you should see malware scan results from Verisys Antivirus API being shown in a web page:

Scan result of a clean, virus-free file

Scan result of an infected file

Code for this tutorial can be found on GitHub: https://github.com/IonxSolutions/tutorial-file-uploads-aspnetcore

💖 💪 🙅 🚩
ionx
Ionx Solutions

Posted on May 7, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related