SfFileManager - How to set the root folder on the fly?

Hi there,

In all real-world scenarios we need this basic functionality:

  1. define an overall root folder within the API (can be hard coded, like you did it in your API demo)
  2. dynamically create subfolders for each user-account or project (on-the-fly, if it does not exists)
  3. set the sub directory as a personal root folder within FileManager component (e.g. "SetRootFolder"), so that you cannot access or view other users' documents

//Data/Files
//Data/Files/User1
//Data/Files/User2
//Data/Files/User3

<SfFileManager SetRootFolder="/User1/">
    <FileManagerAjaxSettings Url="/api/FileData/FileOperations"
                                DownloadUrl="/api/FileData/Download"
                                GetImageUrl="/api/FileData/GetImage"
                                UploadUrl="/api/FileData/Upload">
    FileManagerAjaxSettings>
SfFileManager>

So basically we must inject "SetRootFolder" in the API, somehow:

namespace FileManager.Server.Controllers
{
    [Route("api/[controller]")]
    public class FileDataController : Controller
    {
        public PhysicalFileProvider operation;
        public string basePath;
 
        [Obsolete]
        public FileDataController(IHostingEnvironment hostingEnvironment)
        {
            this.basePath = hostingEnvironment.ContentRootPath;
            this.operation = new PhysicalFileProvider();
 
            //SetRootFolder
            this.operation.RootFolder(this.basePath + "\\wwwroot\\uploads");
        }

How to achive this within SyncFusion Blazor Server?

Any ideas?

Cheers,
Volker



17 Replies

SP Sowmiya Padmanaban Syncfusion Team May 20, 2020 03:46 PM UTC

Hi Volker,  
 
Greetings from Syncfusion support. 
 
Query1 & Query3 -  root folder within the API 
 
Due to security reason, we have not provided property for setting the root path to the FileManager component. You can add the root path of the FileManager in the server side by using if you have access to user information. To achieve your requirement, you can pass the custom attribute( for example: username) to the controller side and set the root path of the FileManager component based on the user.  
 
We have already provided a similar sample in this forum. Refer the sample link below. 
 
 
In the above shared forum, we have changed the root path of the FileManager component based on Dropdown value. Similarly, you can change the root path based on the user. In this case, files/folders will be displayed in the File Manager based on the user details. By this way, Other users cannot access the files/folders which was not specific to them. 
 
Query2 - create subfolders for each user-account. 
 
If you want to create a folder based on your user account. You can get the folder details in GetFiles() method in controller side. Inside the GetFiles(), you can able to check the particular folder is present inside the user or not. If not, you can create a empty folder based on your requirement. 
 
Refer the below link for controller method. 
 
Refer the below forum link in this link, we have override the GetFiles() method in controller side. 
 
 
Please, get back to us if you face any issue when implementing your requirement with FileManager, with problem or requirement details. We will check and provide you the prompt solution needed. 
 
Please let us know, if you need any further assistance. 
 
 
Regards,  
Sowmiya.P 



VO Volker May 21, 2020 06:50 AM UTC

Hi Sowmiya,

thank you so much for your detailed answer.
I'm really impressed by the quality of Syncfusion's support. THANK YOU!
I'll try to solve it this way.

Please don't get me wrong, but... I still think that this is a fundamental requirement of any business case.

So one approach is to tell us developers to customize your extensive API controller, which you provide, to implement "SetRootFolder" (with the meaning of a subfolder of a given, hardcoded root folder, just for security not to spy on the top). In this case, thousands of derivatives are generated, maintenance and version compatibilty will be hard when SyncFusion goes the next step in the API development or again start to change namespaces etc..

On the other hand, when you, being the central authority of your provided high quality components, add this property as a basic functionality and make it available on your server for downloading, all these problems would not arise.

Just a suggestion ...

Cheers,
Volker




SA Shameer Ali Baig Sulaiman Ali Baig Syncfusion Team May 22, 2020 03:01 PM UTC

Hi Volker, 
 
We have checked with your suggestion. As mentioned in our last update, we have not provided property in File Manager to set the root folder in client-side to maintain the security and to protect the data from anonymous access.  
 
Also, we would like to inform you that we will not introduce breaking changes in the existing API service methods, to maintain standard for the file provider API services for our EJ2 File Manager. Even if we introduce any new changes, we will only deprecate the already existing functionality and we won’t remove them from file provider API services. 
 
So, we recommend you use our previously shared solution to achieve your expect requirement with File Manager. If you face any problem on achieving requirement with File Manager, then please share us problem details. We will make every effort to help you solve your reported problem, promptly.  
 
Please, let us know if you need any further assistance. 
 
Regards, 
Shameer Ali Baig S. 



VO Volker May 25, 2020 04:06 PM UTC

Hi Shamir,

when ever I upload an image to wwwroot/files/ and insert it as a link or image in your richtext editor, the full URL path including my subroot folder is visible in the HTML code of the browser anyway. So I can't see the problem of setting the root folder in design/CRM mode of the application on the fly or your security concerns that you don't want to send a plain root path-string to the API over the wire. Who cares if the final website and all of its assets (pdf, jpg, vendor etc.) are visible from the front end, anyway?



Anyway, would you please (PLEASE!!!) be so nice and provide a working example. I haven't got it running so far using C#, your API and Blazor Server.
Sorry




Basically I need this to set a subdirectory within "wwwroot/uploads/:
<SfFileManager SetRootFolder="/b93f06db-1693-4060-8ad4-6e440b0ea369/">
    <FileManagerAjaxSettings Url="/api/FileData/FileOperations"
                                DownloadUrl="/api/FileData/Download"
                                GetImageUrl="/api/FileData/GetImage"
                                UploadUrl="/api/FileData/Upload">
    FileManagerAjaxSettings>
SfFileManager>




Cheers,
Volker


SP Sowmiya Padmanaban Syncfusion Team May 26, 2020 11:01 AM UTC

Hi Volker,  
 
We have checked your query with FileManager component. You can modify the controller method to set the desired root path. 
 
Steps to create a sample and set the root folder: 
 
1.      You can create sever side using this link. 
 
2.      Add the controllers folder and create a controller file inside the folder. 
 
3.      And then create a Models folder,  add the base and physical file provider inside the folder. 
 
4.      In Startup.cs file, you need to map the controller. Refer the below code snippet. 
 
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
{ 
            app.UseEndpoints(endpoints => 
            { 
                endpoints.MapControllers(); 
                endpoints.MapBlazorHub(); 
                endpoints.MapFallbackToPage("/_Host"); 
            }); 
        } 
 
 
5.      You need to set the root path inside the controller side. Refer the below code snippet. 
 
  public class DefaultController : Controller 
    { 
        public PhysicalFileProvider operation; 
        public string basePath; 
        string root = "wwwroot\\Files\\Uploads"; 
 
        [Obsolete] 
        public DefaultController(IHostingEnvironment hostingEnvironment) 
        { 
            this.basePath = hostingEnvironment.ContentRootPath; 
            this.operation = new PhysicalFileProvider(); 
            this.operation.RootFolder(this.basePath + "\\" + this.root); 
        } 
} 
 
 
6.      After setting the root path, it displays only the folder inside the uploads. Refer the below screenshot. 
 
 
Refer the sample link below. 
 
Please let us know, if you need any further assistance. 
 
Regards,  
Sowmiya.P 



VO Volker May 27, 2020 09:08 AM UTC

Hi Sowmiya,

thank your for your detailed answer, very nice.
Please, don't get me wrong, but I know all these things, how to hard-code the base-folder in the controller and how to change this string.

That was not the question.
What I need is to move the root of a file-manager to a given subfolder from the front-end. 

Think about a Blazor-App where I manage some projects.
We define a hard-coded base-folder.
Each project needs some assets like pdfs etc. 
Each project gets it's own subfolder within the base-folder.
The file-manager points to this subfolder, dynamically.

e.g. 
(hard-coded) base-folder:
"wwwroot/Files/Uploads/"

(dynamic) root-folders: 
wwwroot/Files/Uploads/project1
wwwroot/Files/Uploads/project2
wwwroot/Files/Uploads/project3
wwwroot/Files/Uploads/project4

So the base "wwwroot/Files/Uploads/" is hard-coded within the controller due to security reasons as you demonstrated.
But using something like SetRootFolder="project3" I must be able to set the path to this project's subfolder, so that the overall folder of this particular file-manager goes to "wwwroot/Files/Uploads/project3" (base-folder + root-folder):

<SfFileManager SetRootFolder="project3">
    <FileManagerAjaxSettings Url="/api/FileData/FileOperations"
                                DownloadUrl="/api/FileData/Download"
                                GetImageUrl="/api/FileData/GetImage"
                                UploadUrl="/api/FileData/Upload">
    FileManagerAjaxSettings>
SfFileManager>

Please give an example of how this can be achieved.

Thank you so much!

Cheers,
Volker


SP Sowmiya Padmanaban Syncfusion Team May 27, 2020 02:48 PM UTC

Hi Volker,  
 
We have validated your requirement to set the root folder for client side using FileManager component. By default, OnSend is triggered for each FileManager request except GetImage and Download operations. To achieve your requirement, you need to send the root path using OnSend event of FileManager component. 
 
Refer the below code snippet. 
<SfFileManager @ref="Filemanager" ShowThumbnail="false"> 
    <FileManagerEvents OnSend="send" BeforeDownload="beforeDownload"></FileManagerEvents> 
</SfFileManager> 
public void send(BeforeSendEventArgs args) 
    { 
          string AjaxSettingsString = JsonConvert.SerializeObject(args.AjaxSettings); 
          Dictionary<string, dynamic> AjaxSettings = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(AjaxSettingsString); 
            string dataString = AjaxSettings["data"]; 
            Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(dataString); 
            // Fetch the DropDown value. 
            var Rootpath = "wwwroot\\Files\\Uploads"; 
            data.Add("FilePath", Rootpath); 
            string modifiedDataString = JsonConvert.SerializeObject(data); 
            AjaxSettings["data"] = modifiedDataString; 
            string returnString = JsonConvert.SerializeObject(AjaxSettings); 
            args.AjaxSettings = JsonConvert.DeserializeObject<object>(returnString); 
    } 
 
It triggers the controller side method. Inside the method, you have to set the root path for FileManager component. 
 
public class FileManagerDirectoryContent1 
    { 
        public string Path { get; set; } 
 
        public string Action { get; set; } 
            ... 
        public string FilePath { get; set; } 
 
    }  
 public object FileOperations([FromBody] FileManagerDirectoryContent1 args)            
        {      
            this.operation.RootFolder(this.basePath + "\\" + args.FilePath);        
            if (args.Action == "delete" || args.Action == "rename") 
            { 
                if ((args.TargetPath == null) && (args.Path == "")) 
                { 
                    FileManagerResponse response = new FileManagerResponse(); 
                    response.Error = new ErrorDetails { Code = "401", Message = "Restricted to modify the root folder." }; 
                    return this.operation.ToCamelCase(response); 
                } 
            } 
} 
 
In the similar way, you can set the root path of Download operations using beforeDownload method. Refer the below code snippet. 
 
public void beforeDownload(BeforeDownloadEventArgs args) 
    { 
        string data = JsonConvert.SerializeObject(args.Data); 
        Dictionary<string, dynamic> AjaxSettings1 = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(data); 
        AjaxSettings1["FilePath"] = "wwwroot\\Files\\Uploads"; 
        string returnString1 = JsonConvert.SerializeObject(AjaxSettings1); 
        args.Data = JsonConvert.DeserializeObject<object>(returnString1); 
    } 
 
In the following sample, we have set the root path for basic FileManager operations (Read, Delete, Copy, Move, Download, Details). 
 
 
GetImage is processed using query string parameter and it is not implemented using Ajax requests. Can you please whether meets your requirement. Based on your confirmation, we will further check and update the solution for achieving the same for GetImage operation. 
 
Regards,  
Sowmiya.P 



VO Volker May 27, 2020 03:38 PM UTC

Hi Sowmiya,

brilliant. That's the way I can implement my project management...

In your example
"New Folder" works
"Rename" works
"Delete" works
"Cut and Paste" works

Please have a look at "View Large Icons","Open", "Upload" and "Download" to get these things working, too

Cheers,
Volker


SP Sowmiya Padmanaban Syncfusion Team May 28, 2020 08:58 AM UTC

Hi Volker,  
 
Thanks for your confirmation. 
 
As per our previous update, onSend is triggered for each request in the FileManager component. To achieve your requirement, you can save the root path of FileManager component using session variable. By saving the root path in session, we can access the root path for other file operations (Upload, Download, GetImage). 
 
Send the root path to the controller side. 
 
public void send(BeforeSendEventArgs args) 
    { 
        if (args.Action != "Upload") 
        { 
            string AjaxSettingsString = JsonConvert.SerializeObject(args.AjaxSettings); 
            Dictionary<string, dynamic> AjaxSettings = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(AjaxSettingsString); 
            string dataString = AjaxSettings["data"]; 
            Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(dataString); 
            // Fetch the DropDown value. 
            var Rootpath = "wwwroot\\Files\\Uploads"; 
            data.Add("FilePath", Rootpath); 
            string modifiedDataString = JsonConvert.SerializeObject(data); 
            AjaxSettings["data"] = modifiedDataString; 
            string returnString = JsonConvert.SerializeObject(AjaxSettings); 
            args.AjaxSettings = JsonConvert.DeserializeObject<object>(returnString); 
        } 
    } 
 
You need to add the session in Startup.cs file. 
public void ConfigureServices(IServiceCollection services) 
        { 
            services.AddSyncfusionBlazor(); 
            services.AddSession(); 
        } 
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
        { 
            app.UseSession(); 
        } 
 
You need to  store the root path in session variable. Refer the below code snippet. 
  [Route("FileOperations")] 
        public object FileOperations([FromBody] FileManagerDirectoryContent1 args) 
        { 
           // Store the root path in sesssion. 
            HttpContext.Session.SetString("RootPath", args.FilePath);    
            this.operation.RootFolder(this.basePath + "\\" + args.FilePath); 
         } 
 
And then use the root path for remaining operations (Upload, Download, GetImage) using session variable. 
 
Refer the below code snippet. 
[Route("Upload")] 
        public IActionResult Upload(string path, IList<IFormFile> uploadFiles, string action, string FilePath) 
        { 
            var rootpath = HttpContext.Session.GetString("RootPath"); 
            this.operation.RootFolder(this.basePath + "\\" + rootpath); 
} 
[Route("Download")] 
        public IActionResult Download(string downloadInput) 
        { 
            var rootpath = HttpContext.Session.GetString("RootPath"); 
            this.operation.RootFolder(this.basePath + "\\" + rootpath); 
       } 
[Route("GetImage")] 
        public IActionResult GetImage(FileManagerDirectoryContent1 args) 
        { 
            var rootpath = HttpContext.Session.GetString("RootPath"); 
            this.operation.RootFolder(this.basePath + "\\" + rootpath); 
       } 
 
Refer the below video footage for FileManager sample. 
 
Refer the sample link below. 
 
Please let us know, if you need any further assistance. 
 
Regards,  
Sowmiya.P 



VO Volker May 29, 2020 07:41 AM UTC

Hi Sowmiya,

thank you so much. That worked!

fyi, I made same minor changes to meet the desired requirements

1) in the controller
public class myFileManagerDirectoryContent : FileManagerDirectoryContent
{
    public string FilePath { getset; }
}
 
[Route("api/[controller]")]
public class DefaultController : Controller
{
    ...
 
    private const string BASEFOLDER = "wwwroot\\Files\\Uploads\\";
    
    [Route("FileOperations")]
    public object FileOperations([FromBodymyFileManagerDirectoryContent args)
    {
        // Store the root path in session.
        HttpContext.Session.SetString("RootPath", BASEFOLDER + args.FilePath);
 
        var rootpath = HttpContext.Session.GetString("RootPath");
        this.operation.RootFolder(this.basePath + "\\" + rootpath);

2) in the component
<SfFileManager RootAliasName="Your Project">
    <FileManagerEvents OnSend="@(args => Send(args,"b93f06ab-1693-4060-88d4-6e440b0ea369"))">FileManagerEvents>
    <FileManagerAjaxSettings Url="/api/Default/FileOperations"
                             GetImageUrl="/api/Default/GetImage"
                             UploadUrl="/api/Default/Upload"
                             DownloadUrl="/api/Default/Download">
    FileManagerAjaxSettings>
SfFileManager>
 
@code  {
    public void Send(BeforeSendEventArgs args, string Rootpath)
    {
        string AjaxSettingsString = JsonConvert.SerializeObject(args.AjaxSettings);
        Dictionary<stringdynamic> AjaxSettings = JsonConvert.DeserializeObject<Dictionary<stringdynamic>>(AjaxSettingsString);
        string dataString = AjaxSettings["data"];
        Dictionary<stringdynamic> data = JsonConvert.DeserializeObject<Dictionary<stringdynamic>>(dataString);
        data.Add("FilePath", Rootpath);
        string modifiedDataString = JsonConvert.SerializeObject(data);
        AjaxSettings["data"= modifiedDataString;
        string returnString = JsonConvert.SerializeObject(AjaxSettings);
        args.AjaxSettings = JsonConvert.DeserializeObject<object>(returnString);
    }
}

So here we go:


One last question:
Is it possible to open all subfolders within navigation pane on inital load?

One last wish:
Maybe you consider to add SetRootFolder as a property in a future release, cause using sessions in a sessionless concept (Blazor) is not the best way to get things done ;-)

Cheers,
Volker

Attachment: SetRootFolder_ab452b9f.zip


SA Shameer Ali Baig Sulaiman Ali Baig Syncfusion Team June 2, 2020 04:26 PM UTC

Hi Volker, 
 
We have validated your requirement of setting the rootfolder for File Manager from client-side. We have considered your request as feature to be implemented in File Manager. In this planned feature, we will provide option to send custom attribute in all file operation requests of File Manger, using which can achieve your expected requirement in File Manager.  
 
Generally, we will plan the component implementation based on customer request count and wish-list plan. 
 
 
You can track the status of this feature implementation through following link. 
 
 
Query: Is it possible to open all subfolders within navigation pane on inital load?  
 
Solution:  
 
We cannot expand all tree nodes in TreeView available within navigation pane of FileManager, as by default, nested tree nodes for sub folders will be dynamically added to the TreeView based on the available sub folders within the navigated file path in File Manager. 
 
We suspect that you are expecting to render File Manager with nested folder path as its default path using its path property. By using this solution, File Manager will render with default path based on your preferred file path, also based on the folder navigations in the file system, tree node for the navigated path will be expanded on initialization. 
 
 
 
Please, let us know if you need any further assistance. 
 
Regards, 
Shameer Ali Baig S. 



VO Volker June 3, 2020 06:57 AM UTC

Hi there,

cool solution, that's the trick!

One last word:
Syncfusion does a fantastic job, your support of software developers is simply outstanding.

Thank you!

Cheers,
Volker


SP Sowmiya Padmanaban Syncfusion Team June 3, 2020 12:18 PM UTC

Hi Volker,  
  
Most Welcome. We are happy to hear that our provided solution meets your requirement. Please contact us, if you need any help from us. 
  
Regards,  
Sowmiya.P 



VO Volker December 8, 2020 08:33 AM UTC

Hi Sowmiya,

we must migrate all uploads from our Blazor-App root folder to Azure Blob Storage due to some security concerns.

Could you please make a modification to your controller file (where you add the 
Blazor-App root folder option) that you sent me?
btw. is the feature SetRootFolder now available or do we still use the Session work-around?

Thank you so much.

Cheers,
Volker




Attachment: FileDataController_ca246bc2.zip


SP Sowmiya Padmanaban Syncfusion Team December 9, 2020 01:47 PM UTC

Hi Volker,  
 
We have not provided a root folder support for FileManager component. We suggest you to use the session workaround in Azure file provider. 
 
For your reference, we have prepared a sample for Azure blob storage with FileManager. 
 
 
Note: You need to refer the Azure login details in RegisterAzure and setBlobContainer method and pass the blob path and file path in client side and use it in all the methods (AzureUpload, AzureDownalod, AzureGetImage, AzureFileOperations ). 
 
 
public void send(BeforeSendEventArgs args) 
    { 
        if (args.Action != "Upload") 
        { 
            string AjaxSettingsString = JsonConvert.SerializeObject(args.AjaxSettings); 
            Dictionary<string, dynamic> AjaxSettings = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(AjaxSettingsString); 
            string dataString = AjaxSettings["data"]; 
            Dictionary<string, dynamic> data = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(dataString); 
            // Fetch the DropDown value. 
            var FilePath = "filepath"; 
            var Blobpath = "blobpath"; 
            data.Add("BlobPath", Blobpath); 
           data.Add("FilePath", FilePath); 
            string modifiedDataString = JsonConvert.SerializeObject(data); 
            AjaxSettings["data"] = modifiedDataString; 
            string returnString = JsonConvert.SerializeObject(AjaxSettings); 
            args.AjaxSettings = JsonConvert.DeserializeObject<object>(returnString); 
        } 
    } 
 
Controller: 
 
 
  [Obsolete] 
        public HomeController(IHostingEnvironment hostingEnvironment) 
        { 
            this.operation = new AzureFileProvider(); 
            this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); 
       } 
 
 
[Route("AzureFileOperations")] 
        public object AzureFileOperations([FromBody] FileManagerDirectoryContent1 args) 
        { 
            // Store the root path in sesssion. 
            HttpContext.Session.SetString("FilePath", args.FilePath); 
            HttpContext.Session.SetString("Blobpath", args.Blobpath); 
            this.operation.SetBlobContainer(args.Blobpath, args.FilePath); 
            if (args.Path != "") 
            { 
                 
                string startPath = args.Blobpath; 
                string originalPath = (args.FilePath).Replace(startPath, ""); 
                args.Path = (originalPath + args.Path).Replace("//", "/"); 
                args.TargetPath = (originalPath + args.TargetPath).Replace("//", "/"); 
            } 
} 
// Uploads the file(s) into a specified path 
        [Route("AzureUpload")] 
        public ActionResult AzureUpload(FileManagerDirectoryContent args) 
        { 
            var filepath = HttpContext.Session.GetString("FilePath"); 
            var blobpath = HttpContext.Session.GetString("Blobpath"); 
            this.operation.SetBlobContainer(blobpath, filepath); 
            if (args.Path != "") 
            { 
                string startPath = blobpath; 
                string originalPath = (filepath).Replace(startPath, ""); 
                args.Path = (originalPath + args.Path).Replace("//", "/"); 
            } 
            return Json(""); 
        } 
 
Please, refer the below GitHub link for Azure file provider. 
 
 
Please let us know, if you need any further assistance. 
 
Regards, 
Sowmiya.P 



SZ SZL December 5, 2024 10:06 AM UTC

Hello,

I would like to ask, there are a built in way now in new versions to set root folder from View ( SetRootFolder or similar?)

If not, there are a solution to add custom parameter to FileManagerDirectoryContent args from View trough TagHelper?

Thank you!




VM Vishwanathan Muruganantham Syncfusion Team December 6, 2024 12:36 PM UTC

Hi SZL,


Greetings from Syncfusion support


We would like to inform you that we have provided support to send JWT tokens in Read operation from client to server. By using the JWT token, you can send dynamic root folder names from the client-side to the server-side. Based on the retrieved server-side root folder name, you can set dynamic root folders in the FileManager component.


Check the shared sample.


Sample: attached as zip file.


The above sample demonstrates how to pass the root folder from the client-side to the server-side for FileManager read/upload operation. Based on the server-side value, we have changed the FileManager root folder to client1 and client2 dynamically.


Also, we have shared a GitHub sample that contains details related to sending JWT tokens from the client-side to the server-side in all FileManager operations and how to set a dynamic root folder in the FileManager component for your reference.


GitHub sample: https://github.com/SyncfusionExamples/blazor-filemanager-pass-jwt-token


Feedback: https://www.syncfusion.com/feedback/29225/provide-support-to-switch-the-root-folder-dynamically-in-the-blazor-file-manager


Regards,
Vishwanathan


Attachment: BlazorFileManager_a1d0b0d5.zip

Loader.
Up arrow icon