FileUpload
in namespace DotVVM.Framework.Controls
Renders a FileUpload control allowing users to upload one or multiple files asynchronously.
Usage & Scenarios
Allows the user to upload one or multiple files asynchronously.
Upload Configuration
The upload works on the background and starts immediately when the user selects the files. To make file uploading work, you have to specify where the temporary files will be uploaded.
The recommended strategy is to store the uploaded files in your application directory or in the temp directory (if your app have the appropriate permissions).
To define this, you have to register the UploadedFileStorage
in the IDotvvmServiceConfigurator
.
public void ConfigureServices(IDotvvmServiceCollection options)
{
options.AddUploadedFileStorage("App_Data/Temp");
}
Using the Control
Then, you need to bind the FileUpload
control to an UploadedFilesCollection
. It is a collection which will hold references to the files
the user has selected and uploaded.
This collection has a handy property IsBusy
of boolean
which indicated whether the file upload is still in progress. You can use it e.g. on
the button's Enabled
property to disallow the user to continue until the upload is finished.
Retrieving the Stored Files
The files are saved to a temporary location on the server. The UploadedFilesCollection
holds only unique IDs of the files. To get the file contents, you have 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
{
private IUploadedFileStorage storage;
public MyViewModel(IUploadedFileStorage storage)
{
this.storage = storage;
}
...
}
You can then use the GetFile
method to retrieve the Stream
to access the file contents.
foreach (var file in UploadedFiles.Files)
{
if (file.IsAllowed)
{
// get the stream of the uploaded file and do whatever you need to do
var stream = storage.GetFile(file.FileId);
// OR you can just move the file from the temporary storage somewhere else
var targetPath = Path.Combine(uploadPath, file.FileId + ".bin");
storage.SaveAs(file.FileId, targetPath);
// it is a good idea to delete the file from the temporary storage
// it is not required, the file would be deleted automatically after the timeout set in the DotvvmStartup.cs
storage.DeleteFile(file.FileId);
}
}
You should check the FileTypeAllowed
and MaxSizeExceeded
properties before you start to process the files. The file size and extension are validated on the client-side, but an attacker can easily pass these checks.
You should delete the temporary files after they are processed. The files will be deleted automatically from the storage after 30 minutes. You can change this timeout or the specific storage implementation in DotvvmStartup
- instead of calling AddDefaultTempStorages
, just register any implementation of IUploadedFileStorage
in the IServiceCollection
.
Sample 1: Basic FileUpload control
The FileUpload control has the UploadedFiles
property (of type UploadedFilesCollection). Each file will get a unique ID which is stored in this collection.
The AllowMultipleFiles
property specifies whether the user can select multiple files in the file browser window.
<dot:FileUpload UploadedFiles="{value: Files}" AllowMultipleFiles="true" />
using System.Collections.Generic;
using DotVVM.Framework.Controls;
namespace DotvvmWeb.Views.Docs.Controls.builtin.FileUpload.sample1
{
public class ViewModel
{
public UploadedFilesCollection Files { get; set; }
public ViewModel()
{
Files = new UploadedFilesCollection();
}
}
}
Sample 2: UploadCompleted Event
The UploadCompleted
event is fired automatically when file is uploaded.
<dot:FileUpload UploadedFiles="{value: Files}" AllowMultipleFiles="true"
UploadCompleted="{command: ProcessFile()}" />
{{value: Message}}
using System.Collections.Generic;
using DotVVM.Framework.Controls;
namespace DotvvmWeb.Views.Docs.Controls.builtin.FileUpload.sample2
{
public class ViewModel
{
public UploadedFilesCollection Files { get; set; }
public string Message { get; set; }
public ViewModel()
{
Files = new UploadedFilesCollection();
}
public void ProcessFile()
{
// do what you have to do with the uploaded files
Message = "ProcessFile() was called.";
}
}
}
Sample 3: Processing the Files
You can use the Files.IsBusy
property to determine whether the upload is still in progress or not.
<dot:FileUpload UploadedFiles="{value: Files}"
AllowMultipleFiles="true" />
<p>
<dot:Button Text="Save Files"
Click="{command: Process()}"
Enabled="{value: !Files.IsBusy}" />
</p>
using System.IO;
using DotVVM.Framework.Controls;
using DotVVM.Framework.Storage;
using DotVVM.Framework.ViewModel;
namespace DotvvmWeb.Views.Docs.Controls.builtin.FileUpload.sample3
{
public class ViewModel : DotvvmViewModelBase
{
private IUploadedFileStorage storage;
public UploadedFilesCollection Files { get; set; }
public ViewModel(IUploadedFileStorage storage)
{
// use dependency injection to request IUploadedFileStorage
this.storage = storage;
Files = new UploadedFilesCollection();
}
public void Process()
{
var uploadPath = GetUploadPath();
// save all files to disk
foreach (var file in Files.Files)
{
var targetPath = Path.Combine(uploadPath, file.FileId + ".bin");
storage.SaveAs(file.FileId, targetPath);
storage.DeleteFile(file.FileId);
}
// clear the uploaded files collection so the user can continue with other files
Files.Clear();
}
private string GetUploadPath()
{
var uploadPath = Path.Combine(Context.Configuration.ApplicationPhysicalPath, "MyFiles");
if (!Directory.Exists(uploadPath))
{
Directory.CreateDirectory(uploadPath);
}
return uploadPath;
}
}
}
Properties
Name | Type | Description | Notes | Default Value | |
---|---|---|---|---|---|
AllowedFileTypes | String | Gets or sets the types of files that the server accepts. It must be a comma-separated list of unique content type specifiers (eg. ".jpg,image/png,audio/*"). All file types are allowed by default. |
attribute
static value
|
null | |
AllowMultipleFiles | Boolean | Gets or sets whether the user can select multiple files at once. It is enabled by default. |
attribute
static value
|
True | |
Attributes | Dictionary<String,Object> |
attribute
static value
|
null | ||
ClientIDMode | ClientIDMode | Gets or sets the client ID generation algorithm. |
attribute
static value
|
Static | |
DataContext | Object | Gets or sets a data context for the control and its children. All value and command bindings are evaluated in context of this value. |
attribute
static value
bindable
|
null | |
ID | String | Gets or sets the unique control ID. |
attribute
static value
bindable
|
null | |
IncludeInPage | Boolean | Gets or sets whether the control is included in the DOM of the page. |
attribute
bindable
|
True | |
InnerText | String | Gets or sets the inner text of the HTML element. |
attribute
static value
bindable
|
null | |
MaxFileSize | Int32? | Gets or sets the maximum size of files in megabytes (MB). The size is not limited by default. |
attribute
static value
|
null | |
NumberOfFilesIndicatorText | String | Gets or sets the text on the indicator showing number of files. The default value is "{0} files". The number of files will be substituted for the "{0}" placeholder. |
attribute
static value
bindable
|
{0} files | |
SuccessMessageText | String | Gets or sets the text that appears when all files are uploaded successfully. |
attribute
static value
bindable
|
The files were uploaded successfully. | |
UploadButtonText | String | Gets or sets the text on the upload button. The default value is "Upload". |
attribute
static value
bindable
|
Upload | |
UploadedFiles | UploadedFilesCollection | Gets or sets a collection of uploaded files. |
attribute
bindable
|
null | |
UploadErrorMessageText | String | Gets or sets the text that appears when there is an error during the upload. |
attribute
static value
bindable
|
Error occurred. | |
Visible | Boolean | Gets or sets whether the control is visible. |
attribute
bindable
|
True |
Events
Name | Type | Description | |
---|---|---|---|
UploadCompleted | Command | Gets or sets a command that is triggered when the upload is complete. |