TL;DR: Explore the Blazor File Manager’s chunk upload feature. Break large files into manageable pieces to improve upload efficiency and reliability. Key steps include installing dependencies, registering services, and configuring server-side accommodations.
The Syncfusion® Blazor File Manager is a graphical user interface component for managing the file system. It allows users to perform the most common file operations like accessing, editing, and sorting files or folders. This component provides easy navigation to select a file or folder from the file system. It effectively supports both file and folder uploads. However, managing large file uploads efficiently can be quite challenging.
To overcome this issue, we’ve introduced the chunk upload feature in the Blazor File Manager in the 2024 Volume 4 release.
Let’s examine how this feature helps handle large files, with an example to get you started.
Chunk upload is designed to handle large files or folders by breaking them into smaller manageable chunks. This reduces the risk of upload failures due to network interruptions or server timeouts during uploads.
If a network error occurs during upload, only a specific chunk needs to be re-uploaded rather than the entire file, improving reliability and reducing potential upload times.
Multiple chunks can be uploaded simultaneously, making the upload process faster by better using the available bandwidth.
The feature supports resuming uploads with pause and resume options in the upload dialog, so if an upload session is interrupted, it can continue from where it left off rather than starting from scratch.
This feature provides detailed information on the upload progress so that users can see how much of the file has been successfully uploaded and how much is left.
Dividing files into smaller chunks makes the upload process more manageable and efficient. Users benefit from a smoother experience without significant delays, even when uploading large or multiple files in a folder.
First, we need to install the following NuGet dependencies to build the File Manager efficiently.
Syncfusion.Blazor.FileManager Syncfusion.Blazor.Themes
After installing these dependencies, configure them in your app.
Then, open the ~/_Imports.razor file and import the necessary Syncfusion.Blazor namespace for the required components.
@using Syncfusion.Blazor @using Syncfusion.Blazor.FileManager
Then, register the Syncfusion Blazor Service in the ~/Program.cs file of your Blazor Web app. For an app with WebAssembly or Auto (Server and WebAssembly) interactive render mode, register the Syncfusion Blazor service in both ~/Program.cs files of your web app.
.... using Syncfusion.Blazor; .... builder.Services.AddSyncfusionBlazor(); ....
The theme stylesheet and script can be accessed from NuGet through Static Web Assets. Include the stylesheet reference in the <head> section and the script reference at the end of the <body> in the ~/Components/App.razor file.
Refer to the following code example.
<head> .... <link href="_content/Syncfusion.Blazor.Themes/bootstrap5.css" rel="stylesheet" /> </head> .... <body> .... <script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js" type="text/javascript"></script> </body>
Refer to the following code example to implement the chunk upload feature in the Blazor File Manager component.
@using Syncfusion.Blazor.FileManager <SfFileManager TValue="FileManagerDirectoryContent"> <FileManagerUploadSettings ChunkSize="5242880" MaxFileSize="73728000"> </FileManagerUploadSettings> <FileManagerAjaxSettings Url="https://ej2-aspcore-service.azurewebsites.net/api/FileManager/FileOperations" UploadUrl="https://ej2-aspcore-service.azurewebsites.net/api/FileManager/Upload" DownloadUrl="https://ej2-aspcore-service.azurewebsites.net/api/FileManager/Download" GetImageUrl="https://ej2-aspcore-service.azurewebsites.net/api/test/FileManager/GetImage"> </FileManagerAjaxSettings> </SfFileManager>
In the above code example, the ChunkSize is set to 5 MB (5,242,880 bytes), and the MaxFileSize is set to 70 MB (73,728,000 bytes) in the FileManagerUploadSettings. This means files up to 70 MB will be uploaded in 5 MB chunks.
Next, we should manage the upload size within the server-side controller and model files. Refer to the following code example.
Controller.cs
[Route("Upload")] [DisableRequestSizeLimit] public IActionResult Upload(string path, long size, IList<IFormFile> uploadFiles, string action) { try { FileManagerResponse uploadResponse; foreach (var file in uploadFiles) { var folders = (file.FileName).Split('/'); // checking the folder upload if (folders.Length > 1) { for (var i = 0; i < folders.Length - 1; i++) { string newDirectoryPath = Path.Combine(this.basePath + path, folders[i]); if (Path.GetFullPath(newDirectoryPath) != (Path.GetDirectoryName(newDirectoryPath) + Path.DirectorySeparatorChar + folders[i])) { throw new UnauthorizedAccessException("Access denied for Directory-traversal"); } if (!Directory.Exists(newDirectoryPath)) { this.operation.ToCamelCase(this.operation.Create(path, folders[i])); } path += folders[i] + "/"; } } } uploadResponse = operation.Upload(path, uploadFiles, action, size, null); if (uploadResponse.Error != null) { Response.Clear(); Response.ContentType = "application/json; charset=utf-8"; Response.StatusCode = Convert.ToInt32(uploadResponse.Error.Code); Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = uploadResponse.Error.Message; } } catch (Exception e) { ErrorDetails er = new ErrorDetails(); er.Message = e.Message.ToString(); er.Code = "417"; er.Message = "Access denied for Directory-traversal"; Response.Clear(); Response.ContentType = "application/json; charset=utf-8"; Response.StatusCode = Convert.ToInt32(er.Code); Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = er.Message; return Content(""); } return Content(""); }
Models/PhysicalFileProvider.cs
public virtual FileManagerResponse Upload(string path, IList<IFormFile> uploadFiles, string action, long size = 0, params FileManagerDirectoryContent[] data) { FileManagerResponse uploadResponse = new FileManagerResponse(); try { string validatePath; validatePath = Path.Combine(contentRootPath + path); if (Path.GetFullPath(validatePath) != GetFilePath(validatePath)) { throw new UnauthorizedAccessException("Access denied for Directory-traversal"); } AccessPermission PathPermission = GetPathPermission(path); if (PathPermission != null && (!PathPermission.Read || !PathPermission.Upload)) { accessMessage = PathPermission.Message; throw new UnauthorizedAccessException("'" + this.getFileNameFromPath(this.rootName + path) + "' is not accessible. You need permission to perform the upload action."); } List<string> existFiles = new List<string>(); foreach (IFormFile file in uploadFiles) { if (uploadFiles != null) { var name = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim().ToString(); string[] folders = name.Split('/'); string fileName = folders[folders.Length - 1]; var fullName = Path.Combine((this.contentRootPath + path), fileName); if (Path.GetFullPath(fullName) != GetFilePath(fullName) + Path.GetFileName(fullName)) { throw new UnauthorizedAccessException("Access denied for Directory-traversal"); } long fileLength = File.Exists(fullName) ? new FileInfo(fullName).Length : 0; if (action == "save") { bool isValidChunkUpload = file.ContentType == "application/octet-stream" && (fileLength != size); if (!System.IO.File.Exists(fullName) || isValidChunkUpload) { PerformUpload(file, fileLength, size, fullName); } else { existFiles.Add(fullName); } } else if (action == "remove") { if (System.IO.File.Exists(fullName)) { System.IO.File.Delete(fullName); } else { ErrorDetails er = new ErrorDetails(); er.Code = "404"; er.Message = "File not found."; uploadResponse.Error = er; } } else if (action == "replace") { long duplicateFileSize = new FileInfo(fullName).Length; if (System.IO.File.Exists(fullName) && (duplicateFileSize == size || file.ContentType != "application/octet-stream")) { System.IO.File.Delete(fullName); } PerformUpload(file, fileLength, size, fullName); } else if (action == "keepboth") { string newName = fullName; int index = newName.LastIndexOf("."); if (index >= 0) newName = newName.Substring(0, index); int fileCount = 0; while (System.IO.File.Exists(newName + (fileCount > 0 ? "(" + fileCount.ToString() + ")" + Path.GetExtension(name) : Path.GetExtension(name)))) { long duplicateSize = new FileInfo(newName + (fileCount > 0 ? "(" + fileCount.ToString() + ")" + Path.GetExtension(name) : Path.GetExtension(name))).Length; if (duplicateSize == size || file.ContentType != "application/octet-stream") { fileCount++; } else { break; } } newName = newName + (fileCount > 0 ? "(" + fileCount.ToString() + ")" : "") + Path.GetExtension(name); long newFileLength = File.Exists(newName) ? new FileInfo(newName).Length : 0; PerformUpload(file, newFileLength, size, newName); } } } if (existFiles.Count != 0) { ErrorDetails er = new ErrorDetails(); er.Code = "400"; er.Message = "File already exists."; er.FileExists = existFiles; uploadResponse.Error = er; } return uploadResponse; } catch (Exception e) { ErrorDetails er = new ErrorDetails(); er.Message = e.Message.ToString(); er.Code = er.Message.Contains("is not accessible. You need permission") ? "401" : "417"; if ((er.Code == "401") && !string.IsNullOrEmpty(accessMessage)) { er.Message = accessMessage; } uploadResponse.Error = er; return uploadResponse; } } private void PerformUpload(IFormFile file, long fileLength, long size, string name) { bool isValidChunkUpload = file.ContentType == "application/octet-stream" && (fileLength != size); if (file.ContentType == "application/octet-stream") { using (var fileStream = new FileStream(name, FileMode.Append)) { file.CopyTo(fileStream); } } else { using (FileStream fs = System.IO.File.Create(name)) { file.CopyTo(fs); fs.Flush(); } } }
Refer to the following image.
For more details, refer to the chunk upload in the Blazor File Manager component documentation.
Thanks for reading! We hope you enjoyed this quick guide to utilizing the chunk upload feature of Syncfusion® Blazor File Manager. This feature helps us greatly enhance the performance and reliability of file uploads in our web app. Breaking down large files into smaller, manageable pieces as chunks ensures that your apps remain responsive and efficient even under demanding load conditions.
It was rolled out in the Essential Studio® 2024 Volume 4 release. Try out this great feature and provide valuable feedback in the comments section. Check out our Release Notes and What’s New pages to see all the new updates in this release.
Our existing customers can download the latest Essential Studio® version from the License and Downloads page. If you are not a Syncfusion® customer, try our 30-day free trial to check out our newest features.
You can also contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!