This content originally appeared on Telerik Blogs and was authored by Claudio Bernasconi
Learn how to upload files in a Blazor Server web application running on .NET 8.
Uploading customer data, such as a photo for a user profile or a PDF document, is standard in modern web development.
In this Blazor Basics article, we will learn how to upload a file using Blazor Server. This is another example of how Blazor Server makes things astonishingly simple compared to other web development technologies.
You can access the code used in this example on GitHub.
Blazor Component Using InputFile
We implement a Blazor component with a simple HTML template and a single event handler method in this example.
The template code of the Upload
component looks like this:
@page "/upload"
<PageTitle>Blazor Server File Upload</PageTitle>
<h1>Blazor Server File Upload</h1>
<div style="margin-bottom: 20px; display: flex;">
<div>Select your file:</div>
<InputFile OnChange="FileUploaded" />
</div>
<h2>Selected file</h2>
<div>
<div>File name: @FileName</div>
<div>File size: @FileSize.ToString("n0") bytes</div>
<div>File type: @FileType</div>
<div>Last modified: @LastModified</div>
</div>
@if (!string.IsNullOrEmpty(ErrorMessage))
{
<div>Error: @ErrorMessage</div>
}
We use the @page
directive to make the component a routable page. Next, we use the build-in PageTitle
component to set the page title shown in the browser tab.
The core of the HTML template is using the built-in InputFile
component. We provide a method to handle the OnChange
event. We will look at the method implementation of the FileUploaded
method in the next chapter.
<InputFile OnChange="FileUploaded" />
The rest of the component code helps us understand what’s happening and doesn’t need to be used when implementing the file upload.
First, we want to display information about the uploaded file, which will allow us to confirm that we uploaded the correct information.
The last part is more important.
We want to show the user error messages in case the file upload fails. We check whether the ErrorMassage
property contains information and render it in an HTML div
element.
Handling the File Upload
The code section of the Upload
page component contains a single FileUploaded
method, which is used as the callback for the OnChange
event of the FileInput
component.
Additionally, we have a few properties to show detailed information about the uploaded file on the page when the user uploads a file.
@code {
public string FileName { get; set; } = "";
public long FileSize { get; set; }
public string FileType { get; set; } = "";
public DateTimeOffset LastModified { get; set; }
public string ErrorMessage { get; set; } = "";
const int MAX_FILESIZE = 5000 * 1024; // 2 MB
public async Task FileUploaded(InputFileChangeEventArgs e)
{
var browserFile = e.File;
if (browserFile != null)
{
FileSize = browserFile.Size;
FileType = browserFile.ContentType;
FileName = browserFile.Name;
LastModified = browserFile.LastModified;
try
{
var fileStream = browserFile.OpenReadStream(MAX_FILESIZE);
var randomFile = Path.GetTempFileName();
var extension = Path.GetExtension(browserFile.Name);
var targetFilePath = Path.ChangeExtension(randomFile, extension);
var destinationStream = new FileStream(targetFilePath, FileMode.Create);
await fileStream.CopyToAsync(destinationStream);
destinationStream.Close();
}
catch (Exception exception)
{
ErrorMessage = exception.Message;
}
}
}
}
We set the MAX_FILESIZE
constant to 2 megabytes to limit the file size that the user is able to upload.
I highly recommend limiting file sizes. Otherwise, you risk depleting the available storage and, therefore, causing problems with keeping the service running.
The asynchronous FileUploaded
method accepts a single parameter of type InputFileChangeEventArgs
. This type exposes a File
property, which we can use to access the file’s content and meta data.
In this example code, we assign the value from the File
property to a local browserFile
variable. The type is IBrowserFile
.
First, we check if the browserFile
variable contains a value, meaning that a file was selected. We can use the Size
, ContentType
, Name
and LastModified
properties to access meta data.
Next, we use a try-catch
block to catch any IOExceptions
or similar errors during the process of handling the file upload.
We use the OpenReadStream
method and provide the maximum file size constant as its argument.
Next, we use the Path.GetTempFileName
method to create a temporary file on the disk. It’s a location to which most .NET programs will have write access. However, you might want to choose the location on disk that makes most sense to you, depending on your use case.
Note: The example code here write to the local disk, since it’s the simplest approach and it also is independent from other resources.
Another option is to send the information to an API or store it in a database.
We use the GetExtension
and ChangeExtension
methods to create a proper target file path.
Next, we create a FileStream
object and provide the intended file path and the FileMode.Create
enum value as the second argument to the constructor.
We use the CopyToAsync
method on the created file stream to copy the content of the uploaded file to the file stream on the local disk. We also need to make sure we call the Close
method to close the stream and release all the resources, such as sockets and file handles.
In the catch block, we simply access the Message
property on the Exception
and set its content to the ErrorMessage
property that we show on the screen.
Note: You might want to implement proper error handling in a real application, such as logging the error and showing the user a generic error message to prevent an attack from exploiting your application.
Uploading Multiple Files
Sometimes, we want to allow multiple files to be uploaded together. For example, for a social media post or a house listing.
Adding the multiple
HTML attribute to the InputFile
component is all we need to do in the component template.
Next, we change the event handler method to deal with multiple files.
public async Task FileUploaded(InputFileChangeEventArgs e)
{
var browserFiles = e.GetMultipleFiles();
foreach( var browserFile in browserFiles)
{
if (browserFile != null)
{
FileSize = browserFile.Size;
FileType = browserFile.ContentType;
FileName = browserFile.Name;
LastModified = browserFile.LastModified;
try
{
var fileStream = browserFile.OpenReadStream(MAX_FILESIZE);
var randomFile = Path.GetTempFileName();
var extension = Path.GetExtension(browserFile.Name);
var targetFilePath = Path.ChangeExtension(randomFile, extension);
var destinationStream = new FileStream(targetFilePath, FileMode.Create);
await fileStream.CopyToAsync(destinationStream);
destinationStream.Close();
}
catch (Exception exception)
{
ErrorMessage = exception.Message;
}
}
}
}
First, instead of using the File
property on the InputFileChangeEventArgs
type, we use the GetMultipleFiles
method. This method returns an IReadOnlyList
of IBrowserFile
.
Using a foreach
statement, we loop through the files in this list and run the same code for each file that we previously used for handling a single file upload.
Note: Of course, the file information on the screen will now only show the data from the last processed file.
Best Practices for File Uploads
When working with user content, such as uploaded files, we need to be careful and apply security best practices.
As previously stated in this article, limiting the file size is an important security consideration. We do not want to provide the user the option to deplete the available storage.
Checking the file format and only allowing certain types of content is critical. If you want the user to upload a photo or image, make sure you only allows the respective content.
We should also check the content of the files for viruses or other unsafe content if we accept risky formats, such as PDF documents that can contain executable code.
There is a File Upload Cheat Sheet that includes the best practices from OSWAP.
Blazor WebAssembly Considerations
In this article, we discuessed how to implement file upload for Blazor Server. Blazor Server, with its always-running on the server architecture, makes it especially simple to implement a file upload.
When running on WebAssembly, we do not have direct access to the server from the client code.
Instead, we need to call an API to handle the file upload server-side. There are many cloud services, such as Azure Storage Account, or you can implement custom services.
On the upside, we can reuse the component template. The InputFile
component and the OnChange
event handler method can be reused.
However, instead of writing to the local disk, we want to call an API and provide the content we read from the InputFileChangeEventArgs
method argument.
Conclusion
File uploading is a common task in a modern web application. Blazor Server makes it simple to implement a file upload using the built-in InputFile
component.
Depending on if we add the multiple
HTML attribute (or not) to the InputFile
component, we can handle a single or multiple files.
We can resuse some of the code for Blazor WebAssembly but we need to remember that the code executes on the client and, therefore, we need to call an API to handle the files on the server.
You can access the code used in this example on GitHub.
If you want to learn more about Blazor development, you can watch my free Blazor Crash Course on YouTube. And stay tuned to the Telerik blog for more Blazor Basics.
This content originally appeared on Telerik Blogs and was authored by Claudio Bernasconi
Claudio Bernasconi | Sciencx (2024-07-31T15:04:17+00:00) Blazor Basics: Uploading Files in Blazor Server Web Applications. Retrieved from https://www.scien.cx/2024/07/31/blazor-basics-uploading-files-in-blazor-server-web-applications/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.