When developing web applications, it is common to need functionalities for adding images or files, such as user profile pictures, product images, attached documents, and more. Implementing this functionality efficiently and securely is essential for a good user experience and system integrity. In this article, we will explore how to configure file uploads in an ASP.NET MVC application, covering practical scenarios such as saving files to the local file system and storing them in a database.
Configuring the Controller for File Upload
Create a controller named “FileUploadController” with the following actions:
public class FileUploadController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public async Task Upload(IFormFile file)
{
// Code to receive the file.
}
}
In the code above, we created two actions in the “FileUploadController.” The first, “Index,” is responsible for displaying the form for file submission, where the user can select the desired file.
The second action, “Upload,” receives the file submitted by the form. We use the “IFormFile” interface, which encapsulates the file data sent by the client and allows direct access on the server side.
Now, let’s detail the implementation of the logic in the “Upload” action to process the file sent by the user. This method follows steps to validate the file and securely save the content.
Validating the File
The first validation checks whether a valid file was sent:
if (file == null || file.Length == 0)
{
ModelState.AddModelError("", "Select a valid file.");
return View("Index");
}
If the received file is null or has zero size, the system will display an error message indicating the issue and redirect the user back to the initial screen (Index). This prevents processing invalid uploads.
Extension Validation
Now let’s add a validation to accept only files with certain extensions:
var allowedExtensions = new[] { ".jpg", ".png", ".pdf" };
var extension = Path.GetExtension(file.FileName).ToLower();
if (!allowedExtensions.Contains(extension))
{
ModelState.AddModelError("", "File format not allowed.");
return View("Index");
}
At this stage, we allow only files with .jpg, .png, and .pdf extensions. Any other format will be rejected with an error message. This protects the application from malicious file uploads.
Maximum File Size Validation
Additionally, we enforce a maximum file size limit:
if (file.Length > 5 * 1024 * 1024)
{
ModelState.AddModelError("", "The file cannot exceed 5 MB.");
return View("Index");
}
To prevent server overload and unwanted uploads, we set a size limit (5 MB). Larger files will be rejected with an appropriate message.
Storing the File in the Application
After adding validations, we store the file in the application, ensuring that the destination folder exists before saving the file.
First, define the directory where the files will be stored:
var uploadDirectory = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/uploads");
Here, we specify that files will be saved in the “wwwroot/uploads” folder. If this folder does not exist, we can create it as follows:
if (!Directory.Exists(uploadDirectory))
{
Directory.CreateDirectory(uploadDirectory);
}
This check prevents errors in case the folder is not yet created on the server or in development environments.
Next, define the full path for the file:
var filePath = Path.Combine(uploadDirectory, file.FileName);
Now, use a FileStream to write the file data to the specified location:
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
This operation writes the file asynchronously, ensuring the application remains responsive during the file upload process.
TempData["Message"] = "File uploaded successfully!";
return RedirectToAction("Index");
After saving the file, you can implement a procedure to save the file information (name, extension, etc.) in the database. Then, we store a success message in “TempData” and redirect the user back to the initial screen.
Creating the Upload Form View
Now let’s create the “Index.cshtml” view with our form:
In the code above, we create a form that sends the data to the “Upload” action in the “FileUpload” controller.
Below, we add messages to be returned in case of an error or success:
@if (TempData["Message"] != null)
{
@TempData["Message"]
}
@foreach (var error in ViewData.ModelState.Values.SelectMany(v => v.Errors))
{
@error.ErrorMessage
}
With this implementation, our images will be saved within our application. However, we can also save them in a database.
Storing Files in a Database
To save an image directly in a database, you can create an entity “FileRecord” to store file information. The “Data” property stores the actual file data in binary format (byte array).
public class FileRecord
{
public int Id { get; set; }
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Data { get; set; }
}
Now, we can modify the “Upload” action to process the received file:
public async Task Upload(IFormFile file)
{
using var memoryStream = new MemoryStream();
await file.CopyToAsync(memoryStream);
var fileRecord = new FileRecord
{
FileName = file.FileName,
ContentType = file.ContentType,
Data = memoryStream.ToArray()
};
context.FileRecords.Add(fileRecord);
await context.SaveChangesAsync();
return RedirectToAction("Index");
}
Security Tips
File Type Validation: Check the extension.
Size Limitation: Define a size limit to prevent server overload.
Avoid File Overwriting: Use unique names (e.g., GUIDs).
Isolated Storage: Save files outside the client-accessible directory if possible.
Conclusion
File uploads in an ASP.NET MVC application can be configured for different storage scenarios. This guide covered everything from basic configuration to database integrations. Be sure to validate files and follow best practices to prevent vulnerabilities.