DotVVM: upload files using FileUpload control
Tags: dotvvm, azure, dotnet, csharp
Published: 2020-04-07 15:09:43

In this post I will show you how it is so easy in [DotVVM](https://www.dotvvm.com/) to upload files to a local folder or even to a blob container in your Azure Storage Account using [FileUpload](https://www.dotvvm.com/docs/controls/builtin/FileUpload/latest) control.

#### Uploading files to Local storage.

1. Create Empty DotVVM web project in visual studio.
    <kbd>![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q6t3nlr909kafzgx6of8.png)</kbd>

2. Open _DotvvmStartup.cs_ file and add the following line to _ConfigureServices_ methods if not exist.

    `options.AddDefaultTempStorages("temp");`
 
    This line is telling DotVVM to set the the default temporary storage to _temp_ folder. Once you try to upload any file DotVVM will create that folder in the root directory of your application.

3. Open _ViewModels/DefaultViewModel_ file and replace its content with the following code.

    ```
using DotVVM.Framework.Controls;
....
namespace DotVVMUploader.ViewModels
{
    public class DefaultViewModel : MasterPageViewModel
    {
        public string Title { get; set; }
        public UploadedFilesCollection FilesCollection { get; set; }
        public DefaultViewModel()
        {
            Title = "Welcome to upload files sample";
            FilesCollection = new UploadedFilesCollection();
        }
    }
}
```

    We defined _FilesCollection_ property as _UploadedFilesCollection_. This property will contain our uploaded files.

4. Open _Views/Default.dothtml_ file and add the following code.
    ```
<dot:FileUpload UploadedFiles="{value: FilesCollection}"
                AllowMultipleFiles="true"
                AllowedFileTypes=".png,.jpg"
                SuccessMessageText="Uploaded"
                UploadButtonText="Select Files to Upload"></dot:FileUpload>
```
    Here, we are adding _FileUpload_ control and set its properties as follows
    - _UploadFiles_ : set to _FilesCollection_ collection we have defined in the ViewModel class. 
    - _AllowMultipleFiles_ : set to true to be able to upload many files at once.
    - _AllowedFileTypes_ : set to restrict the file types you allow user to upload.
    - _SuccessMessageText_ : the message you want to display in the page to inform the user that the upload is finished with no error.
    - _UploadButtonText_ : the text you want to display as a text for upload button.

    **By default DotVVM will save your file with _.tmp_ extension and keep it for 30 minutes then will be deleted automatically.**

5. To save your files to a permanent location/storage you need to do that by yourself.
   In the _FileUpload_ control markup will set _UploadCompleted_ attribute with the name of the event that will be triggered once the upload is completed.

    ```
<dot:FileUpload UploadedFiles="{value: FilesCollection}"
                    AllowMultipleFiles="true"
                    AllowedFileTypes=".png,.jpg"
                    SuccessMessageText="Uploaded"
                    UploadButtonText="Select Files to Upload"
                    UploadCompleted="{command: SaveMyFilesLocally()}"></dot:FileUpload>
```

6. You need to inject _IUploadedFileStorage_ to _DefaultViewModel_ class.
    ```
private readonly IUploadedFileStorage _uploadedFileStorage;
...
public DefaultViewModel(IUploadedFileStorage uploadedFileStorage)
{
      _uploadedFileStorage = uploadedFileStorage;
}
```

7. And here _SaveMyFilesLocally()_ method that we added in _FileUpload_ markup.
    ```
public void SaveMyFilesLocally()
{
   if (!FilesCollection.IsBusy)
   {
      var permenentPath = Path.Combine(Context.Configuration.ApplicationPhysicalPath, "ProcessedFiles");
      if (!Directory.Exists(permenentPath))
      {
          Directory.CreateDirectory(permenentPath);
      }
      foreach (var file in FilesCollection.Files)
      {
           var newFileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}_{file.FileId}{Path.GetExtension(file.FileName)}";
            var filePath = Path.Combine(permenentPath, newFileName);
            _uploadedFileStorage.SaveAs(file.FileId, filePath);
            _uploadedFileStorage.DeleteFile(file.FileId);
       }
       FilesCollection.Clear();
   }
}
```
- First we check if _FilesCollection_ is busy with uploading files. If not, we start to process our uploaded files by looping over _Files_ property of our _FilesCollection_.
- After saving our file to permanent storage we delete it from the temp folder. Deleting files from temp folder is not necessary as DotVVM will delete it after 30 minutes but it is good to do to specially if your application upload huge number of files.
- Then we clear our _FilesCollection_ to not process the same files again if we uploaded another set of files.

Here is how our sample page looks like
<kbd>![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9qmoeyk5yu18jfkcimmq.png)</kbd>

#### Uploading files to Azure Storage Account.
Here is the magic of DotVVM begins. If any point of time you decided to upload your file to the Azure Storage Account instead of local storage, what all you need is modify _SaveMyFilesLocally_ method.

**For demonstration purpose we will add a new method _SaveMyFilesToAzure_ and let _FileUpload_ point to it.**
```
<dot:FileUpload UploadedFiles="{value: FilesCollection}"
                    AllowMultipleFiles="true"
                    AllowedFileTypes=".png,.jpg"
                    SuccessMessageText="Uploaded"
                    UploadButtonText="Select Files to Upload"
                    UploadCompleted="{command: SaveMyFilesToAzure()}"></dot:FileUpload>
```
1. Install _WindowsAzure.Storage_ nuget package
    ```
Install-Package WindowsAzure.Storage
```
2. Add the following using statement to _DefaultViewModel_ class.
    ```
using Microsoft.WindowsAzure.Storage;
```
3. Add _SaveMyFilesToAzure_ method to _DefaultViewModel_ class
    ```
public async Task SaveMyFilesToAzure()
{
    if (!FilesCollection.IsBusy)
    {
        var stoageAccount = CloudStorageAccount.DevelopmentStorageAccount;
        var blobStorageClient = stoageAccount.CreateCloudBlobClient();
        var container = blobStorageClient.GetContainerReference("dotvvmblobcontainer");
        await container.CreateIfNotExistsAsync();
        foreach (var file in FilesCollection.Files)
        {
            var newFileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}_{file.FileId}{Path.GetExtension(file.FileName)}";
            var blobRef = container.GetBlockBlobReference(newFileName);
            await blobRef.UploadFromFileAsync($"temp/uploadedFiles/{file.FileId}.tmp");
        }
        FilesCollection.Clear();
    }
}
```
As you see it is almost the same as before. We just creating a client to Azure Storage Account. 
**Here I'm using the Storage Account Emulator. Explaining how to use it is out of the scope of this article. You can refer to [Microsoft Documentations](https://docs.microsoft.com/en-us/azure/storage/common/storage-use-emulator) for more details.** 

#### Summary
In this post we demonstrated how it is pretty easy to upload files with DotVVM FileUpload Control to your local storage and to your Azure Blob Container.

You can find the full code on [Github](https://github.com/miroprocessor/dotvvm-uploadfiles)