From ce4b1772da1b2bb4e19d44d2d856024bf5ce57d7 Mon Sep 17 00:00:00 2001
From: Dimo Dimov <961014+dimodi@users.noreply.github.com>
Date: Thu, 13 Mar 2025 14:59:50 +0200
Subject: [PATCH] docs(FileManager): Revamp Upload example
---
components/filemanager/upload.md | 415 +++++++++++++------------
components/upload/events.md | 4 +-
components/upload/overview.md | 4 +-
knowledge-base/upload-preview-image.md | 4 +-
4 files changed, 221 insertions(+), 206 deletions(-)
diff --git a/components/filemanager/upload.md b/components/filemanager/upload.md
index bf09941b12..337b21f5b6 100644
--- a/components/filemanager/upload.md
+++ b/components/filemanager/upload.md
@@ -12,7 +12,7 @@ position: 17
The FileManager allows uploading of files through an integrated Upload component. The Upload shows in a dialog when the user clicks on the [`Upload` Toolbar button](slug:filemanager-toolbar).
->tip Before continuing, make sure you are familiar with the features and API of the [Upload component](slug:upload-overview).
+>tip Before you continue, make sure you are familiar with the features and API of the [Telerik Upload component](slug:upload-overview).
Configure the integrated Upload through the `FileManagerUploadSettings` child tag of `FileManagerSettings`. The FileManager exposes parameter names that are identical to the respective Upload component API members:
@@ -22,11 +22,13 @@ Configure the integrated Upload through the `FileManagerUploadSettings` child ta
## Example
-The example below demonstrates how to handle successful upload on the FileManager. Note the following milestones:
+The example below demonstrates how to handle successful uploads in the FileManager. Note the following milestones:
-* To actually **upload** the file, [implement a controller method](slug:upload-overview#implement-controller-methods).
-* To save the file in the **correct folder**, use the [Upload's `OnUpload` event](slug:upload-events#onupload) and send the FileManager's `Path` value to the controller.
-* To receive an optional **custom response** from the controller, use the [Upload's `OnSuccess` event arguments](slug:upload-events#onsuccess).
+* To upload the file, [implement a controller method](slug:upload-overview#implement-controller-methods).
+* To save the file to the correct folder, use the [Upload's `OnUpload` event](slug:upload-events#onupload) and send the FileManager's `Path` value to the controller.
+* To receive an optional custom response from the controller, use the [Upload's `OnSuccess` event arguments](slug:upload-events#onsuccess).
+
+The `FileManagerController` class below assumes that the project name and namespace is `TelerikBlazorApp`. The FileManager `Data` is the contents of the application's `wwwroot` folder.
>caption Using FileManager Upload
@@ -35,246 +37,160 @@ The example below demonstrates how to handle successful upload on the FileManage
````RAZOR
@using System.IO
+@inject NavigationManager NavigationManager
+
+
Path: @FileManagerPath
+
+ @bind-Path="@FileManagerPath">
-
-
+
@code {
- private List FileManagerData = new List();
+ private List FileManagerData { get; set; } = new();
- private string RootPath { get; set; } = "root-folder-path";
- private string DirectoryPath { get; set; } = "root-folder-path";
+ private string FileManagerPath { get; set; } = string.Empty;
- private async Task OnUploadUpload(UploadEventArgs args)
+ // The source root folder for FileManagerData
+ private readonly string RootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
+
+ private string ToAbsoluteUrl(string url)
{
- // Send the correct save location to the Upload controller
- args.RequestData.Add("FileManagerPath", DirectoryPath);
+ return string.Concat(NavigationManager.BaseUri, url);
}
- private async Task OnUploadSuccess(UploadSuccessEventArgs args)
+ private void OnFileManagerUploadRequest(UploadEventArgs args)
{
- await UploadAsync(args, DirectoryPath);
+ // If FileManagerPath is empty, the controller action will not be hit
+ string pathToSend = string.IsNullOrEmpty(FileManagerPath) ? "/" : FileManagerPath;
+
+ args.RequestData.Add("FileManagerPath", pathToSend);
}
- private async Task UploadAsync(UploadSuccessEventArgs args, string path)
+ private async Task OnFileManagerUploadSuccess(UploadSuccessEventArgs args)
{
- await Task.Delay(300);
+ FileManagerData = await GetFileManagerData();
- var uploadFiles = args.Files;
+ // OR
+ // you can add or remove items in FileManagerData manually
+ // depending on the value of args.Operation and args.Files
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ FileManagerData = await GetFileManagerData();
+ }
- // Optional: use information from the Upload controller response
- //var uploadResponse = args.Request.ResponseText;
+ #region FileManager Data Generation
- var files = uploadFiles
- .Select(x => new FlatFileEntry()
- {
- Name = Path.GetFileNameWithoutExtension(x.Name),
- IsDirectory = false,
- HasDirectories = false,
- DateCreated = DateTime.Now,
- DateCreatedUtc = DateTime.Now,
- DateModified = DateTime.Now,
- DateModifiedUtc = DateTime.Now,
- Path = Path.Combine(path, x.Name),
- Extension = Path.GetExtension(x.Name),
- Size = x.Size
- })
- .ToList();
-
- var directory = GetDirectory(path);
- var directoryItems = FileManagerData;
-
- for (int i = 0; i < files.Count; i++)
- {
- var file = files[i];
- directoryItems.Add(file);
- }
+ private async Task> GetFileManagerData()
+ {
+ // Simulate async operation
+ await Task.CompletedTask;
- RefreshData();
+ return ReadFileSystem();
}
- private FlatFileEntry GetDirectory(string path)
+ private List ReadFileSystem()
{
- var directory = FileManagerData.FirstOrDefault(x => x.IsDirectory && x.Path == path);
+ var items = new List();
- return directory;
+ string rootPath = Path.Combine(RootPath);
+ DirectoryInfo rootDirectory = new(rootPath);
+
+ AddChildren(items, rootDirectory, null);
+
+ return items;
}
- private void RefreshData()
+ private void AddDirectory(List items, DirectoryInfo directoryInfo, string? parentId)
{
- FileManagerData = new List(FileManagerData);
+ FileManagerItem directoryEntry = ConvertToFileManagerItem(directoryInfo, parentId);
+ items.Add(directoryEntry);
+
+ AddChildren(items, directoryInfo, directoryEntry.Id);
}
- protected override async Task OnInitializedAsync()
+ private void AddChildren(List items, DirectoryInfo directoryInfo, string? directoryId)
{
- FileManagerData = await GetFlatFileEntries();
+ IEnumerable files = directoryInfo.EnumerateFiles();
+ foreach (FileInfo file in files)
+ {
+ FileManagerItem item = ConvertToFileManagerItem(file, directoryId);
+ items.Add(item);
+ }
+
+ IEnumerable directories = directoryInfo.EnumerateDirectories();
+ foreach (DirectoryInfo directory in directories)
+ {
+ AddDirectory(items, directory, directoryId);
+ }
}
- //initialize the model to allow new folder creation
- private FlatFileEntry OnModelInitHandler()
+ private FileManagerItem ConvertToFileManagerItem(DirectoryInfo directory, string? parentId)
{
- var item = new FlatFileEntry();
- item.Name = $"New folder";
- item.Size = 0;
- item.Path = Path.Combine(DirectoryPath, item.Name);
- item.IsDirectory = true;
- item.HasDirectories = false;
- item.DateCreated = DateTime.Now;
- item.DateCreatedUtc = DateTime.Now;
- item.DateModified = DateTime.Now;
- item.DateModifiedUtc = DateTime.Now;
+ var item = new FileManagerItem()
+ {
+ ParentId = parentId,
+ Name = directory.Name,
+ IsDirectory = true,
+ HasDirectories = directory.GetDirectories().Count() > 0,
+ DateCreated = directory.CreationTime,
+ DateCreatedUtc = directory.CreationTimeUtc,
+ DateModified = directory.LastWriteTime,
+ DateModifiedUtc = directory.LastWriteTimeUtc,
+ // Trim the path to avoid exposing it
+ Path = directory.FullName.Substring(directory.FullName.IndexOf(RootPath) + RootPath.Length),
+ Extension = directory.Extension,
+ // Hard-coded for simplicity, otherwise requires recursion
+ Size = 2 * 1024 * directory.GetFiles().LongCount()
+ };
return item;
}
- // The FileManager is hard-coded, so you can explore the component more easily
- private async Task> GetFlatFileEntries()
+ private FileManagerItem ConvertToFileManagerItem(FileInfo file, string? parentId)
{
+ var item = new FileManagerItem()
+ {
+ ParentId = parentId,
+ Name = Path.GetFileNameWithoutExtension(file.FullName),
+ IsDirectory = false,
+ HasDirectories = false,
+ DateCreated = file.CreationTime,
+ DateCreatedUtc = file.CreationTimeUtc,
+ DateModified = file.LastWriteTime,
+ DateModifiedUtc = file.LastWriteTimeUtc,
+ // Trim the path to avoid exposing it
+ Path = file.FullName.Substring(file.FullName.IndexOf(RootPath) + RootPath.Length),
+ Extension = file.Extension,
+ Size = file.Length
+ };
- var workFiles = new FlatFileEntry()
- {
- Id = "1",
- ParentId = null,
- Name = "Work Files",
- IsDirectory = true,
- HasDirectories = true,
- DateCreated = new DateTime(2022, 1, 2),
- DateCreatedUtc = new DateTime(2022, 1, 2),
- DateModified = new DateTime(2022, 2, 3),
- DateModifiedUtc = new DateTime(2022, 2, 3),
- Path = Path.Combine(RootPath, "Work Files"),
- Size = 3 * 1024 * 1024
- };
-
- var Documents = new FlatFileEntry()
- {
- Id = "2",
- ParentId = workFiles.Id,
- Name = "Documents",
- IsDirectory = true,
- HasDirectories = false,
- DateCreated = new DateTime(2022, 1, 2),
- DateCreatedUtc = new DateTime(2022, 1, 2),
- DateModified = new DateTime(2022, 2, 3),
- DateModifiedUtc = new DateTime(2022, 2, 3),
- Path = Path.Combine(workFiles.Path, "Documents"),
- Size = 1024 * 1024
- };
-
- var Images = new FlatFileEntry()
- {
- Id = "3",
- ParentId = workFiles.Id,
- Name = "Images",
- IsDirectory = true,
- HasDirectories = false,
- DateCreated = new DateTime(2022, 1, 2),
- DateCreatedUtc = new DateTime(2022, 1, 2),
- DateModified = new DateTime(2022, 2, 3),
- DateModifiedUtc = new DateTime(2022, 2, 3),
- Path = Path.Combine(workFiles.Path, "Images"),
- Size = 2 * 1024 * 1024
- };
-
- var specification = new FlatFileEntry()
- {
- Id = "4",
- ParentId = Documents.Id,
- Name = "Specification",
- IsDirectory = false,
- HasDirectories = false,
- Extension = ".docx",
- DateCreated = new DateTime(2022, 1, 5),
- DateCreatedUtc = new DateTime(2022, 1, 5),
- DateModified = new DateTime(2022, 2, 3),
- DateModifiedUtc = new DateTime(2022, 2, 3),
- Path = Path.Combine(Documents.Path, "Specification.docx"),
- Size = 462 * 1024
- };
-
- var report = new FlatFileEntry()
- {
- Id = "5",
- ParentId = Documents.Id,
- Name = "Monthly report",
- IsDirectory = false,
- HasDirectories = false,
- Extension = ".xlsx",
- DateCreated = new DateTime(2022, 1, 20),
- DateCreatedUtc = new DateTime(2022, 1, 20),
- DateModified = new DateTime(2022, 1, 25),
- DateModifiedUtc = new DateTime(2022, 1, 25),
- Path = Path.Combine(Documents.Path, "Monthly report.xlsx"),
- Size = 538 * 1024
- };
-
- var dashboardDesign = new FlatFileEntry()
- {
- Id = "6",
- ParentId = Images.Id,
- Name = "Dashboard Design",
- IsDirectory = false,
- HasDirectories = false,
- Extension = ".png",
- DateCreated = new DateTime(2022, 1, 10),
- DateCreatedUtc = new DateTime(2022, 1, 10),
- DateModified = new DateTime(2022, 2, 13),
- DateModifiedUtc = new DateTime(2022, 2, 13),
- Path = Path.Combine(Images.Path, "Dashboard Design.png"),
- Size = 1024
- };
-
- var gridDesign = new FlatFileEntry()
- {
- Id = "7",
- ParentId = Images.Id,
- Name = "Grid Design",
- IsDirectory = false,
- HasDirectories = false,
- Extension = ".jpg",
- DateCreated = new DateTime(2022, 1, 12),
- DateCreatedUtc = new DateTime(2022, 1, 12),
- DateModified = new DateTime(2022, 2, 13),
- DateModifiedUtc = new DateTime(2022, 2, 13),
- Path = Path.Combine(Images.Path, "Grid Design.jpg"),
- Size = 1024
- };
-
- var files = new List()
- {
- workFiles,
-
- Documents,
- specification,
- report,
-
- Images,
- dashboardDesign,
- gridDesign
- };
-
- return await Task.FromResult(files);
+ return item;
}
- public class FlatFileEntry
+ #endregion FileManager Data Generation
+
+ public class FileManagerItem
{
- public string Id { get; set; }
- public string ParentId { get; set; }
- public string Name { get; set; }
+ public string Id { get; set; } = Guid.NewGuid().ToString();
+ public string? ParentId { get; set; }
+
+ public string Name { get; set; } = string.Empty;
+ public string Extension { get; set; } = string.Empty;
public long Size { get; set; }
- public string Path { get; set; }
- public string Extension { get; set; }
+ public string Path { get; set; } = string.Empty;
+
public bool IsDirectory { get; set; }
public bool HasDirectories { get; set; }
+
public DateTime DateCreated { get; set; }
public DateTime DateCreatedUtc { get; set; }
public DateTime DateModified { get; set; }
@@ -282,11 +198,108 @@ The example below demonstrates how to handle successful upload on the FileManage
}
}
````
+````C# FileManagerController.cs
+using Microsoft.AspNetCore.Mvc;
+
+namespace TelerikBlazorApp.Controllers
+{
+ [ApiController]
+ [Route("api/[controller]/[action]")]
+ public class FileManagerController : ControllerBase
+ {
+ public IWebHostEnvironment HostingEnvironment { get; set; }
+
+ public FileManagerController(IWebHostEnvironment hostingEnvironment)
+ {
+ HostingEnvironment = hostingEnvironment;
+ }
+
+ [HttpPost]
+ public async Task Save(IFormFile files, [FromForm] string fileManagerPath)
+ {
+ if (files != null)
+ {
+ try
+ {
+ if (fileManagerPath.StartsWith("/"))
+ {
+ // Path.Combine ignores the first argument if the second one is an absolute path
+ fileManagerPath = fileManagerPath.Substring(1);
+ }
+
+ var saveLocation = Path.Combine(new string[] { HostingEnvironment.WebRootPath, fileManagerPath, files.FileName });
+
+ using (var fileStream = new FileStream(saveLocation, FileMode.Create))
+ {
+ await files.CopyToAsync(fileStream);
+ }
+ }
+ catch (Exception ex)
+ {
+ Response.StatusCode = 500;
+ await Response.WriteAsync($"Upload failed: {ex.Message}");
+ }
+ }
+
+ return new EmptyResult();
+ }
+
+ [HttpPost]
+ public async Task Remove([FromForm] string files, [FromForm] string fileManagerPath)
+ {
+ if (files != null)
+ {
+ try
+ {
+ if (fileManagerPath.StartsWith("/"))
+ {
+ fileManagerPath = fileManagerPath.Substring(1);
+ }
+
+ var fileLocation = Path.Combine(HostingEnvironment.WebRootPath, fileManagerPath, files);
+
+ if (System.IO.File.Exists(fileLocation))
+ {
+ System.IO.File.Delete(fileLocation);
+ }
+ }
+ catch (Exception ex)
+ {
+ Response.StatusCode = 500;
+ await Response.WriteAsync($"Delete failed: {ex.Message}");
+ }
+ }
+
+ return new EmptyResult();
+ }
+ }
+}
+````
+````C# Program.cs
+// ...
+
+var builder = WebApplication.CreateBuilder(args);
+
+// ...
+
+builder.Services.AddControllers();
+
+var app = builder.Build();
+
+// ...
+
+app.MapDefaultControllerRoute();
+
+// ...
+
+app.Run();
+````
## Next Steps
* [Upload Events](slug:upload-events)
* [Upload Validation](slug:upload-validation)
+* [Upload Troubleshooting](slug:upload-troubleshooting)
## See Also
diff --git a/components/upload/events.md b/components/upload/events.md
index 55e106b07c..f7109a3636 100644
--- a/components/upload/events.md
+++ b/components/upload/events.md
@@ -490,7 +490,7 @@ public async Task Save(IFormFile files)
## Example
-The `UploadController` class below assumes that the project name and namespace is `TelerikBlazorUpload`.
+The `UploadController` class below assumes that the project name and namespace is `TelerikBlazorApp`.
Make sure to enable controller routing in the app startup file (`Program.cs`). In this case, `app.MapDefaultControllerRoute();` is all that's needed.
@@ -688,7 +688,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace TelerikBlazorUpload.Controllers
+namespace TelerikBlazorApp.Controllers
{
[Route("api/[controller]/[action]")]
public class UploadController : ControllerBase
diff --git a/components/upload/overview.md b/components/upload/overview.md
index a831b22eb0..3c4d597afb 100644
--- a/components/upload/overview.md
+++ b/components/upload/overview.md
@@ -78,7 +78,7 @@ Request routing depends on the application and is outside the Upload component s
Also check the [Upload Troubleshooting](slug:upload-troubleshooting) page.
-The `UploadController` class below assumes that the project name and namespace is `TelerikBlazorUpload`.
+The `UploadController` class below assumes that the project name and namespace is `TelerikBlazorApp`.
>caption Sample Upload Controller
@@ -92,7 +92,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace TelerikBlazorUpload.Controllers
+namespace TelerikBlazorApp.Controllers
{
[Route("api/[controller]/[action]")]
public class UploadController : ControllerBase
diff --git a/knowledge-base/upload-preview-image.md b/knowledge-base/upload-preview-image.md
index 8615d429d4..f326162686 100644
--- a/knowledge-base/upload-preview-image.md
+++ b/knowledge-base/upload-preview-image.md
@@ -47,6 +47,8 @@ In Blazor, [previewing images is easier when using the FileSelect](#using-the-fi
You cannot preview the image in the Upload `OnSelect` event, because this event handler has no access to the file contents.
+The `UploadController` class below assumes that the project name and namespace is `TelerikBlazorApp`.
+
>caption Preview uploaded images when using the Upload component
@@ -130,7 +132,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-namespace TelerikBlazorUpload.Controllers
+namespace TelerikBlazorApp.Controllers
{
[Route("api/[controller]/[action]")]
public class UploadController : ControllerBase