File uploads and downloads are essential features for many applications. Whether you’re handling document uploads, image downloads, or large file exchanges, .NET 8 Minimal APIs provide an efficient way to manage file transfers seamlessly. In this guide, I'll show you exactly how to handle file uploads and downloads in Minimal APIs with a focus on simplicity, security, and scalability.
Let’s dive in and explore how to make your Minimal API file-ready in no time!
Why Handle File Uploads and Downloads in Minimal APIs?
Adding file upload and download capabilities enhances your API by:
- Supporting user uploads like documents, photos, and videos.
- Enabling data exchange for files that clients need to access, modify, or archive.
- Improving UX by enabling secure and efficient file handling directly within your API.
Minimal APIs, known for their lightweight and straightforward design, are an excellent choice for building file transfer functionality into modern applications without complex overhead.
1. Setting Up a Minimal API Project for File Handling
To get started, let’s create a .NET 8 Minimal API project. Open your terminal and run:
dotnet new web -n FileUploadDownloadDemo
cd FileUploadDownloadDemo
Open Program.cs
, where we’ll define the endpoints for file uploads and downloads.
2. Handling File Uploads in Minimal APIs
In Minimal APIs, handling file uploads is simple using IFormFile
. This allows you to access the file data as it’s uploaded and process it accordingly.
Step 1: Creating the File Upload Endpoint
Let’s create an endpoint to accept file uploads. Add the following code in Program.cs
:
app.MapPost("/upload", async (IFormFile file) =>
{
if (file.Length > 0)
{
var filePath = Path.Combine("Uploads", file.FileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
return Results.Ok(new { FilePath = filePath });
}
return Results.BadRequest("Invalid file.");
});
This code saves the uploaded file to a folder named Uploads. If the file is successfully saved, it returns the file path; otherwise, it responds with a BadRequest.
Step 2: Configuring File Storage
Make sure to create the Uploads
directory in your project root. You can configure file storage by setting permissions and paths in your application’s configuration, ensuring that sensitive data is handled securely.
3. Handling File Downloads in Minimal APIs
File downloads are straightforward in Minimal APIs. We’ll create an endpoint that serves a file when requested, making it accessible to clients for download.
Step 1: Creating the File Download Endpoint
Add the following code in Program.cs
to enable file downloads:
app.MapGet("/download/{fileName}", (string fileName) =>
{
var filePath = Path.Combine("Uploads", fileName);
if (!File.Exists(filePath))
{
return Results.NotFound("File not found.");
}
var fileBytes = File.ReadAllBytes(filePath);
return Results.File(fileBytes, "application/octet-stream", fileName);
});
This endpoint looks for the requested file in the Uploads folder. If found, it returns the file with an appropriate MIME type (application/octet-stream
for generic binary data), which triggers a download prompt in most browsers.
4. Best Practices for Secure and Efficient File Handling
When handling file uploads and downloads, there are several best practices to keep in mind for security and performance:
a. Limit File Sizes
To prevent large files from overloading your server, set a maximum file size limit. You can configure this in your application’s settings:
builder.Services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 10 * 1024 * 1024; // 10 MB
});
b. Validate File Types
Restricting file types can help prevent malicious files from being uploaded. Here’s an example of basic file validation:
if (!file.ContentType.StartsWith("image/"))
{
return Results.BadRequest("Only image files are allowed.");
}
c. Store Files Securely
Store files in directories with limited permissions and avoid placing them in public directories to prevent unauthorized access. You may also consider storing files in a cloud storage solution like Azure Blob Storage or AWS S3 for better scalability.
d. Use Streaming for Large Files
For large files, use streaming to avoid memory issues. This is especially useful for file downloads where loading the entire file into memory is inefficient.
Example of a download with streaming:
app.MapGet("/download-stream/{fileName}", async (string fileName, HttpContext httpContext) =>
{
var filePath = Path.Combine("Uploads", fileName);
if (!File.Exists(filePath))
{
return Results.NotFound("File not found.");
}
httpContext.Response.ContentType = "application/octet-stream";
httpContext.Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{fileName}\"");
await using var stream = new FileStream(filePath, FileMode.Open);
await stream.CopyToAsync(httpContext.Response.Body);
});
This approach sends the file in chunks, reducing memory usage.
5. Testing File Uploads and Downloads
Testing file upload and download functionality is crucial. Here’s a basic example using Postman:
-
File Upload:
- Set the HTTP method to POST and enter the URL:
http://localhost:5000/upload
. - In the Body tab, select form-data, enter
file
as the key, and upload a sample file.
- Set the HTTP method to POST and enter the URL:
-
File Download:
- Set the HTTP method to GET and enter the URL:
http://localhost:5000/download/yourfile.jpg
. - Send the request, and you should receive the file as a downloadable response.
- Set the HTTP method to GET and enter the URL:
Automate these tests where possible to ensure your file handling logic is robust and consistent.
6. Extending File Uploads and Downloads with Authentication
For most applications, file access should be restricted to authorized users. Here’s a basic example of securing these endpoints with JWT authentication:
app.MapPost("/upload", [Authorize] async (IFormFile file) =>
{
// File upload logic here
});
app.MapGet("/download/{fileName}", [Authorize] (string fileName) =>
{
// File download logic here
});
With [Authorize], only authenticated users can access the file upload and download endpoints. You’ll need to configure authentication in your Minimal API project and ensure clients provide a valid JWT.
7. Handling File Uploads and Downloads in the Cloud
For scalability, consider using cloud storage providers like Azure Blob Storage or AWS S3. Here’s a quick example of how to upload a file to Azure Blob Storage:
builder.Services.AddSingleton(x =>
{
var blobServiceClient = new BlobServiceClient("YourAzureBlobStorageConnectionString");
return blobServiceClient.GetBlobContainerClient("uploads");
});
app.MapPost("/upload", async (IFormFile file, BlobContainerClient containerClient) =>
{
var blobClient = containerClient.GetBlobClient(file.FileName);
using var stream = file.OpenReadStream();
await blobClient.UploadAsync(stream, true);
return Results.Ok($"File uploaded to {blobClient.Uri}");
});
This code uploads the file to an Azure Blob Storage container, and you can retrieve it using the blob’s URI. Cloud storage provides secure, scalable storage ideal for large or frequently accessed files.
Conclusion
With Minimal APIs in .NET 8, handling file uploads and downloads is efficient and flexible. By following best practices for security, scalability, and performance, you can build robust file handling capabilities into your APIs.
This guide covered:
- Setting up upload and download endpoints in Minimal APIs.
- Securing file uploads with size limits, type validation, and authentication.
- Streaming large files to reduce memory usage.
- Using cloud storage solutions for scalable file handling.
Whether you’re building a simple file-sharing feature or integrating with cloud storage, .NET 8 Minimal APIs make it easy to manage files reliably.
By mastering these techniques, you’ll be equipped to add efficient file handling to any .NET API, ensuring your application is responsive, secure, and scalable.