Upload files
DotVVM contains the FileUpload control which implements the asynchronous file upload mechanism.
The upload works on the background and starts immediately when the user selects the files. The progress is reported to the user (via a CSS-styleable user interface), and the user can work with the page while the files are being uploaded.
When the upload is complete, unique IDs of the files stored on the server are written in a UploadedFilesCollection
object in the viewmodel, which can be used to access the file contents.
Upload configuration
To make file uploads work, you need to specify where the temporary files will be uploaded.
The recommended strategy is to store the uploaded files in your application directory, or in some temp directory (if your app have the appropriate permissions).
The default project template specifies the default configuration of the uploaded files storage in DotvvmStartup.cs
. It registers a storage for uploaded files, as well as a storage for returned files.
public void ConfigureServices(IDotvvmServiceCollection options)
{
options.AddDefaultTempStorage("temp");
// this is equivalent to registering both uploaded and returned file storage
// options.AddUploadedFileStorage("temp");
// options.AddReturnedFileStorage("temp");
}
The default storage creates a temp
folder in your app directory, and stores uploaded files there. In order to prevent unlimited growth of this folder, the files are deleted after 30 minutes. You can change the default timeout to some other value:
public void ConfigureServices(IDotvvmServiceCollection options)
{
options.AddDefaultTempStorage("temp", TimeSpan.FromMinutes(10));
}
Alternatively, you can provide a different implementation of IUploadedFileStorage
- for example store files in Azure Blob Storage.
public void ConfigureServices(IDotvvmServiceCollection options)
{
options.Services.AddSingleton<IUploadedFileStorage, MyCustomUploadedFileStorage>();
}
UploadedFilesCollection
The FileUpload control needs to specify a UploadedFilesCollection
.
This object contains several properties:
Files
property is a list with entries for all uploaded filesFileId
property contains a unique id of the file on the serverFileName
property contains a name of the file on the user's computerFileSize
provides info about the size of the file (number of bytes, and a human-readable value representing the file size )
IsBusy
andProgress
properties indicate whether something is being uploaded at the moment, and the progress in percents (0 to 100)Error
property contains an error message indicating if there was a problem during the upload
While files are being uploaded, DotVVM regularly updates the contents of the collection.
Process the stored files
The files are saved to a temporary location on the server. The UploadedFilesCollection
holds only unique IDs of the files.
To access the file contents, you need to retrieve them using the IUploadedFileStorage
object.
The simplest way to interact with IUploadedFileStorage
service is to request it as a parameter in the viewmodel constructor.
public class MyViewModel : DotvvmViewModelBase
{
private readonly IUploadedFileStorage storage;
public MyViewModel(IUploadedFileStorage storage)
{
this.storage = storage;
}
...
}
You can then use the GetFileAsync
method to retrieve the Stream
to access the file contents.
foreach (var file in UploadedFiles.Files)
{
// get the stream of the uploaded file and do whatever you need to do
var stream = await storage.GetFileAsync(file.FileId);
// OR you can just move the file from the temporary storage somewhere else
await storage.SaveAsAsync(file.FileId, "some-target-path/myfile.bin");
// it is a good idea to delete the file from the temporary storage
// the file would be deleted automatically after the timeout set in the DotvvmStartup.cs (default is 30 minutes)
await storage.DeleteFileAsync(file.FileId);
}
Be very careful if you use the FileName
property - an attacker may tamper with the file name in attempt to submit executable code to your server to a location where it will be executed. We recommend to always generate file names on your own, and use the FileName
property supplied by the user only in the Content-Disposition
header when you want to allow the file be downloaded later.
The
FileUpload
control allows to restrict the uploaded files to only specific content types, and also allows to limit the size of the file. However, the check happens in the browser, so you should always validate files that come to your application.
Request body limits in ASP.NET
When files are uploaded, the default limits of the ASP.NET platform come in place.
In ASP.NET Core, there are two limits which can prevent the files from being uploaded:
- Kestrel maximum request body size is 30 MB by default.
You can change the limit in Program.cs
:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureKestrel((context, options) =>
{
// Handle requests up to 50 MB
options.Limits.MaxRequestBodySize = 52428800;
});
- Multipart body length limit is 128 MB by default.
You can change the limit in the ConfigureServices
method in Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<FormOptions>(options =>
{
// Set the limit to 256 MB
options.MultipartBodyLengthLimit = 268435456;
});
}
- If you are running on IIS, make sure to configure the request filtering limit too:
<configuration>
<system.webServer>
<security>
<requestFiltering>
<!-- 256 -->
<requestLimits maxAllowedContentLength="268435456" /> // specified in bytes
</requestFiltering>
</security>
</system.webServer>
</configuration>
If you have problems uploading large files, check if there are any other limits on request length imposed by the web server or a reverse proxy.