DxUpload Class

An Upload component.

Namespace: DevExpress.Blazor

Assembly: DevExpress.Blazor.v21.2.dll

Declaration

public class DxUpload :
    DxComponentBase<UploadJSInteropProxy>,
    IUploadJSInteropProxyServer,
    IJSCallback,
    IUploadViewOwner,
    IRequireSelfCascading

Remarks

The DevExpress Upload for Blazor (<DxUpload>) allows users to upload files to the server. Users can select files in the open file dialog or drag and drop files to the drop zone.

Upload Overview

Run Demo: Upload - Overview

Add an Upload to a Project

Follow the steps below to add the Upload component to an application:

  1. Use a DevExpress Project Template to create a new Blazor Server or Blazor WebAssembly application. If you use a Microsoft project template or already have a Blazor project, configure your project to incorporate DevExpress Blazor components.
  2. Add the <DxUpload>...</DxUpload> markup to your application.
  3. Connect the Upload to the server.
  4. Create a controller on the server.
  5. Specify other Upload options (see the sections below).

How File Upload Works

Once a user selected a file, the Upload packs the file into an Ajax request and sends this request to the server (the upload controller).

Upload Progress Bars

The controller’s upload action processes this file and sends a response to the Upload. The Upload displays the response result, for instance, shows the Uploaded text if the file was uploaded successfully.

Upload - The file was uploaded successfully

Users can click the cancel button to interrupt file upload and remove files from the list. To hide the cancel button, set the AllowCancel property to false.

The SelectedFilesChanged event occur each time the file list is changed. You can also handle other events to respond to file upload. Set the ShowFileList property to false to hide the file list.

Connect the Upload to the Server

  1. Specify the Upload’s Name property. Its value is required to access uploaded files on the server.
  2. Set the UploadUrl property to a path of a server-side controller’s action that processes upload requests.
<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/">
</DxUpload>

Create an Upload Controller on the Server

Follow the steps below to create an Upload controller:

  1. Create a separate Web API application and add a controller to it.
  2. Implement a controller action.
  3. Create the wwwroot folder in the project.
  4. Optional. Enable cross-origin requests (CORS). Do this for projects with a controller and an Upload component on different servers.

Implement a Controller Action

Create a controller action that accepts the uploaded file, checks it, and saves it to the target location on a server. Follow the steps below to do this:

  1. Add the Controllers folder to your project.
  2. Right-click on the Controllers folder and select Add Controller.
  3. In the invoked window, select MVC Controller - Empty and click Add.
  4. Rename the controller (for example, UploadController) and click Add.

Do one of the following to access the uploaded file:

  • Create an action with a parameter whose name matches the Name property value.

    public ActionResult UploadFile(IFormFile myFile) {
        // ...
    }
    
  • Use the Name property value to get the uploaded file from form variables.

    public ActionResult UploadFile() {
        // ...
        var myFile = Request.Form.Files["myFile"];
        // ...
    }
    

The following example demonstrates how to implement the upload controller:

using Microsoft.AspNetCore.Mvc;
// Add the following using statements if you use .NET5
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;

[Route("api/[controller]")]
public class UploadController : ControllerBase {
    private readonly IWebHostEnvironment _hostingEnvironment;

    public UploadController(IWebHostEnvironment hostingEnvironment) {
        _hostingEnvironment = hostingEnvironment;
    }

    [HttpPost]
    [Route("UploadFile")]
    // "myFile" is the value of the Upload's "Name" property.
    public ActionResult UploadFile(IFormFile myFile) {
        try {
            // Specify the target location for the uploaded files.
            var path = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
            // Check whether the target directory exists; otherwise, create it.
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            using (var fileStream = System.IO.File.Create(Path.Combine(path, myFile.FileName))) {
                // Check the file here (its extension, safety, and so on). 
                // If all checks are passed, save the file.
                myFile.CopyTo(fileStream);
            }
        } catch {
            Response.StatusCode = 400;
        }
        return new EmptyResult();
    }
}

Enable CORS for a Web API Application

For security reasons, browsers do not allow web pages to send requests to different domains (the same-origin policy). The Upload component’s and the Web API applications cannot communicate if you use them on different servers due to different domains.

To enable cross-origin requests, configure the Web API application as explained below. You can omit this step if you publish projects with the controller and Upload component on the same server.

  1. In the Startup.cs (.NET5) or Program.cs (.NET6) file, specify the CORS policy name and call the AddCors method to apply this policy. Call the UseCors method to add the CORS middleware.

    // ...
    public class Startup {
        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
    
        public void ConfigureServices(IServiceCollection services) {
            // ...
            services.AddCors(options => {
                    options.AddPolicy(MyAllowSpecificOrigins,
                    builder => {
                        builder.AllowAnyOrigin();
                    });
                });
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
            ILoggerFactory loggerFactory) {
            // ...
            // Keep the following order of the middleware
            app.UseCors(MyAllowSpecificOrigins);
            app.UseAuthorization();
            // ...
        }
    }
    
  2. Apply the EnableCors attribute to the Upload controller with the policy name specified above.

    [ApiController]
    [EnableCors("_myAllowSpecificOrigins")]
    [Route("api/[controller]")]
    public class UploadController : ControllerBase {
        // ...
    }
    

If you deploy your application on IIS web server, enable CORS in the server’s web.config file:

<system.webServer>  
<cors enabled="true" failUnlistedOrigins="true">  
    <add origin="\*" />  
</cors>
</system.webServer>

Chunk Upload for Large Files

The Upload can split large files into small packets and send them to the server in multiple requests (one by one). To enable chunk upload, set the ChunkSize property to a positive value that specifies the packet size in bytes.

<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/"
          ChunkSize="1000000">
</DxUpload>

You should configure your upload controller to process file chunks. To access the uploaded file, use the Upload’s Name property value. To get information about the file chunk, use chunk metadata serialized to a JSON object (see the ChunkMetadata class in the example below).

To access file and chunk metadata, use any of the following ways:

  • Create an action with two parameters. The first parameter’s name should match the Name property value. The second parameter should be a string that defines chunk metadata serialized to JSON.

    using System.Text.Json;
    
    public ActionResult UploadChunkFile(IFormFile myFile, string chunkMetadata) {
        // ...
        var metaDataObject = JsonConvert.DeserializeObject<ChunkMetadata>(chunkMetadata);
        // ...
    }
    
  • Get the uploaded file and chunk metadata from form variables.

    using System.Text.Json;
    
    public ActionResult UploadChunkFile() {
        // ...
        var myFile = Request.Form.Files["myFile"];
        var chunkMetadata = Request.Form["chunkMetadata"];
        var metaDataObject = JsonConvert.DeserializeObject<ChunkMetadata>(chunkMetadata);
        // ...
    }
    

In the upload action, merge chunks and save the resulting file to the target location.

using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

// Declare a class that stores chunk details.
public class ChunkMetadata {
    public int Index { get; set; }
    public int TotalCount { get; set; }
    public int FileSize { get; set; }
    public string FileName { get; set; }
    public string FileType { get; set; }
    public string FileGuid { get; set; }
}

[Route("api/[controller]")]
public class UploadController : ControllerBase {
    private readonly IWebHostEnvironment _hostingEnvironment;

    public UploadController(IWebHostEnvironment hostingEnvironment) {
        _hostingEnvironment = hostingEnvironment;
    }

    [HttpPost]
    // "myFile" is the value of the Upload's "Name" property.
    public ActionResult UploadChunkFile(IFormFile myFile, string chunkMetadata) {
        // Specify the location for temporary files.
        var tempPath = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
        // Remove temporary files.
        RemoveTempFilesAfterDelay(tempPath, new TimeSpan(0, 5, 0));

        try {
            if (!string.IsNullOrEmpty(chunkMetadata)) {
                // Get chunk details.
                var metaDataObject = JsonConvert.DeserializeObject<ChunkMetadata>(chunkMetadata);
                // Specify the full path for temporary files (inluding the file name).
                var tempFilePath = Path.Combine(tempPath, metaDataObject.FileGuid + ".tmp");
                // Check whether the target directory exists; otherwise, create it.
                if (!Directory.Exists(tempPath))
                    Directory.CreateDirectory(tempPath);
                // Append the chunk to the file.
                AppendChunkToFile(tempFilePath, myFile);
                // Save the file if all chunks are received.
                if (metaDataObject.Index == (metaDataObject.TotalCount - 1))
                    SaveUploadedFile(tempFilePath, metaDataObject.FileName);
            }
        } catch {
            return BadRequest();
        }
        return Ok();
    }
    void AppendChunkToFile(string path, IFormFile content) {
        using(var stream = new FileStream(path, FileMode.Append, FileAccess.Write)) {
            content.CopyTo(stream);
        }
    }
    void SaveUploadedFile(string tempFilePath, string fileName) {
        var path = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
        System.IO.File.Copy(tempFilePath, Path.Combine(path, fileName));
    }
    void RemoveTempFilesAfterDelay(string path, TimeSpan delay) {
        var dir = new DirectoryInfo(path);
        if(dir.Exists)
            foreach(var file in dir.GetFiles("*.tmp").Where(f => f.LastWriteTimeUtc.Add(delay) < DateTime.UtcNow))
                file.Delete();
    }
}

Users can pause and cancel file upload. To hide the pause and cancel buttons, set the AllowPause and AllowCancel properties to false.

Upload Chunk Upload

Run Demo: Upload - Chunk Upload

Drag and Drop

To enable drag and drop in the Upload, implement an external zone where users can drop a file to upload. Use the following properties to define the drop zone UI:

<div id="overviewDemoDropZone" class="card custom-drop-zone jumbotron w-100 m-0">
    <svg version="1.1" id="_x31_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 42 42" style="enable-background:new 0 0 42 42;" xml:space="preserve">
        <style type="text/css">
            .st0{fill-rule:evenodd;clip-rule:evenodd;}
        </style>
        <g id="_x32_">
            <path id="_x33_" class="st0" d="M34,42H8c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h19l11,11v27C38,40.2,36.2,42,34,42z M27,4v7h7L27,4z
            M34,14H24V4H8v34h26V14z" />
        </g>
        <g id="_x31_2"><path id="_x33__1_" class="st0" d="M28,26h-5v8h-2h-2v-8h-5l7-7L28,26z" /></g>
    </svg>
    <span>Drag and Drop File Here</span>
</div>
<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/"
          ExternalDropZoneCssSelector="#overviewDemoDropZone"
          ExternalDropZoneDragOverCssClass="bg-light border-secondary text-dark">
</DxUpload>

Upload Drag And Drop

Run Demo: Upload - Overview

Multiple File Upload

Set the AllowMultiFileUpload property to true to enable users to upload multiple files at once (asynchronously).

<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/"
          AllowMultiFileUpload="true">
</DxUpload>

Upload Multi File Upload

Run Demo: Upload - Multiple File Selection

Upload Modes

The Upload uploads files after a user selects or drops them (UploadMode.Instant). Set the UploadMode property to UploadMode.OnButtonClick to upload files after the user clicks the upload button.

<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/" 
          UploadMode="UploadMode.OnButtonClick">
</DxUpload>

Upload Use Buttons Mode

Run Demo: Upload - Upload Modes

Validation

Client-Side Validation

Use the following Upload properties to validate uploaded files on the client:

<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/"
          AllowedFileExtensions="@(new List<string> { ".jpg", ".jpeg", ".gif", ".png" })" 
          MaxFileSize="4000000">
</DxUpload>

If validation fails, the Upload displays an error message.

Upload Validation

Run Demo: Upload - Validation

Server-Side Validation

You can also validate uploaded files on the server side (in the controller action). The following example shows how to check file extensions:

using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
public class UploadController : ControllerBase {
    private readonly IWebHostEnvironment _hostingEnvironment;

    public UploadController(IWebHostEnvironment hostingEnvironment) {
        _hostingEnvironment = hostingEnvironment;
    }

    [HttpPost]
    // "myFile" is the value of the Upload's "Name" property.
    public ActionResult UploadImage(IFormFile myFile) {
        try {
            // Specify the allowed file extensions. 
            string[] imageExtensions = { ".jpg", ".jpeg", ".gif", ".png" };
            // Check the accepted file's extension.
            var fileName = myFile.FileName.ToLower();
            var isValidExtenstion = imageExtensions.Any(ext => {
                return fileName.LastIndexOf(ext) > -1;
            });
            // Save the file if it passed validation.
            if(isValidExtenstion) {
                var path = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
                if(!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                using(var fileStream = System.IO.File.Create(Path.Combine(path, myFile.FileName))) {
                    myFile.CopyTo(fileStream);
                }
            }
        } catch {
            Response.StatusCode = 400;
        }

        return new EmptyResult();
    }
}

Select Button Customization

Use the SelectButtonText property to change the Select File button’s text.

<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/"
          SelectButtonText="Select My File">
</DxUpload>

Upload Select Button Custom Text

To hide the select button, set the ShowSelectButton property to false.

You can also implement an external select button that invokes the open file dialog. Use the ExternalSelectButtonCssSelector to specify the CSS selector of a button or another HTML element.

The following example demonstrates how to implement the external Select File button and drop zone container. Handle the SelectedFilesChanged event and use the Visible property to hide the Upload when the file list is empty.

<div id="overviewDemoDropZone" class="card custom-drop-zone bg-light rounded-3 w-100 m-0">
    <svg version="1.1" id="_x31_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 42 42" style="enable-background:new 0 0 42 42;" xml:space="preserve">
        <style type="text/css">
            .st0{fill-rule:evenodd;clip-rule:evenodd;}
        </style>
        <g id="_x32_">
            <path id="_x33_" class="st0" d="M34,42H8c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h19l11,11v27C38,40.2,36.2,42,34,42z M27,4v7h7L27,4z
            M34,14H24V4H8v34h26V14z" />
        </g>
        <g id="_x31_2"><path id="_x33__1_" class="st0" d="M28,26h-5v8h-2h-2v-8h-5l7-7L28,26z" /></g>
    </svg>
    <span>Drag and Drop File Here</span><span class="m-1">or</span>
    <button id="overviewDemoSelectButton" class="btn border-primary btn-primary m-1">Select File</button>
</div>
<DxUpload Name="myFile" UploadUrl="https://localhost:10000/api/Upload/UploadFile/" 
          Visible="@UploadVisible" 
          ExternalSelectButtonCssSelector="#overviewDemoSelectButton" 
          ExternalDropZoneCssSelector="#overviewDemoDropZone"
          ExternalDropZoneDragOverCssClass="custom-drag-over border-light text-white" 
          SelectedFilesChanged="@SelectedFilesChanged">
</DxUpload>

@code {
    bool UploadVisible { get; set; } = false;

    protected void SelectedFilesChanged(IEnumerable<UploadFileInfo> files) {
        UploadVisible = files.ToList().Count > 0;
        InvokeAsync(StateHasChanged);
    }
}

Upload External UI

Run Demo: Upload - Overview

Respond to File Upload

Handle the following events to respond to file upload process:

Event

Description

FileUploadStart

Fires when file upload is about to start.

FileUploadStarted

Fires when file upload starts.

FileUploaded

Fires when a file is uploaded successfully.

FileUploadAborted

Fires when file upload is aborted.

FileUploadPaused

Fires when file upload is paused.

FileUploadError

Fires when an error occurs during file upload.

FileReloaded

Fires when a file is reloaded.

FileUploadProgressChanged

Fires when the upload progress changes.

Troubleshooting

If a Blazor application throws unexpected exceptions, refer to the following help topic: Troubleshooting.

Inheritance

Object
ComponentBase
DevExpress.Blazor.Base.DxAsyncDisposableComponent
DevExpress.Blazor.Base.DxDecoratedComponent
DxComponentBase
DxComponentBase<DevExpress.Blazor.Internal.JSInterop.UploadJSInteropProxy>
DxUpload
See Also