Ionx Solutions
Posted on May 7, 2024
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:
- .NET SDK 8 installed on your machine
- Basic knowledge of .NET, ASP.NET Core and C#
- An IDE or text editor; we'll use Visual Studio 2022 for this tutorial, but a lightweight IDE such as Visual Studio Code will work just as well
To allow files to be uploaded, you will:
- Create ASP.NET Core Razor views that allow the user to select a file to upload
- 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
- Enter Web for the Project Name, choose a location to save the project, then click Next
- For the Framework, select .NET 8.0 (Long Term Support), then click Create
- The new project will be created, and you should see this folder structure in Visual Studio's 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:
- The first time you run the project, you will be asked to install an SSL/TLS certificate - click Yes on both popups:
- Visual Studio will then run the app, opening it in the default 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.
File Upload
To enable file uploads, we need to add:
- View models, to encapsulate information about uploaded files
- A view with a form that allows users to select and upload a file
- A view to show information about the uploaded file
- A controller, to show the views and handle the uploaded file
- 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 }
- Next, create a folder
Views/Upload
, and inside a view fileViews/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>
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>
- 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);
}
}
- 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>
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:
- Click the link Upload File, and you should see one of the new views we created:
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:
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:
- Registration of an HTTP client with the Dependency Injection (DI) container
- A view with a form that allows users to select and upload a file for scanning
- A view to show the results of the malware scan
- A controller, to show the views and send the uploaded file to Verisys Antivirus API
Let's get started!
- In file
Program.cs
, replace linebuilder.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;
});
NOTE:
TheX-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 fileViews/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>
- 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>
}
}
- 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);
}
}
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:
- Click the link Scan File, and you should see one of the new views we created:
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:
Code for this tutorial can be found on GitHub: https://github.com/IonxSolutions/tutorial-file-uploads-aspnetcore
Posted on May 7, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.