I have been going round-and-round with the filemanager in blazor with the AzureProvider.
At one point I had it accessing my Azure Blob storage account and listing the container/folder/blobs within but when I tried to upload a file the file data was null in the AzureUpload method of the AzureProviderController.
I then started over and now get can't even access the AzureProviderController.
Here is the AzureProviderController followed by the Test.Razor page that loads the FileManager. I've replaced my storage service account with Azure_Service_Account in the code. Your help is greatly appreciated.
AzureProviderController.cs
using System;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Syncfusion.EJ2.FileManager.Base;
using Syncfusion.EJ2.FileManager.AzureFileProvider;
namespace API.Controllers
{
[Route("api/[controller]")]
[EnableCors("AllowAllOrigins")]
public class AzureProviderController : Controller
{
public AzureFileProvider operation;
public string blobPath { get; set; }
public string filePath { get; set; }
public AzureProviderController()
{
this.operation = new AzureFileProvider();
blobPath = "https://azure_service_account.blob.core.windows.net/ghostcreroot";
filePath = "https://azure_service_account.blob.core.windows.net/ghostcreroot/properties";
blobPath = (blobPath.Substring(blobPath.Length - 1) != "/") ? blobPath + "/" : blobPath.TrimEnd(new[] { '/', '\\' }) + "/";
filePath = (filePath.Substring(filePath.Length - 1) == "/") ? filePath.TrimEnd(new[] { '/', '\\' }) : filePath;
this.operation.SetBlobContainer(blobPath, filePath);
this.operation.RegisterAzure("azure_service_account", "KQF4qIRsQTi3GF1CmUIpZnu3OF0dZNH5ssV7q/qSZ4QG3vXQ==", "ghostcreroot");
//----------
//For example
//this.operation.setBlobContainer("https://azure_service_account.blob.core.windows.net/files/", "https://azure_service_account.blob.core.windows.net/files/Files");
//this.operation.RegisterAzure("azure_service_account", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "files");
//---------
}
test.razor
@page "/test"
@using GhostCRE.Components.Properties
@using Data.Models
@using Syncfusion.Blazor.FileManager
<SfFileManager TValue="FileManagerDirectoryContent">
<FileManagerAjaxSettings Url="https://localhost:7279/api/AzureProvider/AzureFileOperations"
UploadUrl="https://localhost:7279/api/AzureProvider/AzureUpload"
DownloadUrl="https://localhost:7279/api/AzureProvider/AzureDownload"
GetImageUrl="https://localhost:7279/api/AzureProvider/AzureGetImage">
</FileManagerAjaxSettings>
</SfFileManager>
@code {
}
Hi Carl,
Greetings from Syncfusion support.
The reported issue generally occurs due to CORS policy. We suggest you check once to see whether you are facing a CORS error in the console. If so, to overcome the reported issue, we suggest you follow the below forum to overcome the issue.
https://www.syncfusion.com/forums/165500/random-error-with-filemanager
If not, please check whether you enabled authentication in your application. Kindly share with us whether you have done application level authentication or enabled Windows authentication at your end. Please check the suggested way. If the issue still persists, revert us with the requested details.
Regards,
Indhumathy L
Thank you for the response. There are no CORS policy errors reported. I did have a CORS policy issue originally and added the following to solve that:
app.UseRouting();
app.UseRouting();
app.UseCors(builder =>
builder.WithOrigins("https://localhost:7291"));
app.MapBlazorHub();
app.MapBlazorHub();
{
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
endpoints.MapControllers();
});
The application that calls the API does have authentication put at this point the API project does not
Hi Carl,
From the explanation, we understand that you are using two projects one is with Blazor File Manager and another is with Azure File Service provider. You have enabled authentication at the Blazor File Manager project which is the root cause of the issue.
We have used HttpClient for web API calls in the File Manager to perform all file operations. While enabling authentication, the request send from client end will be failed and our service controller is not triggered. Even the basic HttpClient call has the same issue while including the authentication code. We have already raised a query on GitHub for a fix and are tracking it closely for the solution.
https://github.com/dotnet/aspnetcore/issues/34025
As of now, you can either comment out the authentication related codes in your Startup.cs file, else follow the steps mentioned in the below blog to enable Authentication in Blazor Server side application to avoid the issue.
https://www.syncfusion.com/blogs/post/easy-steps-create-a-blazor-server-app-with-authentication.aspx
We have addressed similar queries in the below forum. Refer to the
following link.
Please check whether the shared details helpful for you and get back to us if you need any further assistance.
Regards,
Indhumathy L
Thank you for the info. I find the documentation on using the Blazor File Manager with Azure Provider confusing.
Would it be possible for you to provide a sample of this? It can be a single project without authentication with the filemanager working in the app to access the Azure Cloud provider which allows me to put in my Azure Storage information.
Thank you.
Hi Carl,
Currently we are preparing FileManager with Azure Provider sample. But we need some additional time and will update you with further details within two business days on August 10, 2022. We appreciate your patience.
Regards,
Prasanth Madhaiyan.
Hi Carl,
Thanks for your patience.
As requested we have prepared a Blazor File Manager sample with Azure File Service provider in latest package version. We have prepared sample without authentication. Please find the sample from below link.
https://www.syncfusion.com/downloads/support/directtrac/general/ze/AZUREF~1-1604893212
You can refer the shared sample to prepare sample at your end. Please get back to us if you need any further assistance.
Regards,
Indhumathy L
Thank you for the sample. I am still having trouble getting this working.
If I have a storage account at https://azure_service_account.blob.core.windows.net
and a container called root
In AzureProviderController what would the blobPath and filePath be list all the folders and files in the container root?
In the RegisterAzure method what would the blobName be?
Thank you.
Hi Carl,
You need to specify the container path in Azure blob storage as blobPath and the Files location path as filePath. For example, we have created a files container in the mentioned Azure blob storage. Inside that container, we have created a new folder Files which includes all files and folders needs to be viewed in FileManager. Please refer to the below path.
|
public AzureProviderController(IHostingEnvironment hostingEnvironment) { this.operation = new AzureFileProvider(); blobPath = "https://azure_service_account.blob.core.windows.net/files/"; filePath = "https://azure_service_account.blob.core.windows.net/files/Files"; |
In a similar way, you can specify the container path and root folder path in the above path details. Please let us know if you need any further assistance.
Regards,
Indhumathy L
Thank you Indhumathy for the sample and assistance. The FileManager is now working.
I do have a further question. I want to use the FileManager to access different containers and blob within my app. How can I dynamically specify the blobPath and filePath?
Hi Carl,
We have validated your requirement in File Manager component. We understood that you want to update the container and root folder in the File Manager by passing user details from client end. We suggest you to follow the below way to achieve your requirement.
Separate Azure container and separate folder names
You can maintain separate containers for separate folders, based on the user name passed to server you can perform some customizations in controller, to view the separate containers of different folders. You need to add the custom_attribute (user_name) in FileManagerDirectoryContent class.
Please check the below code snippet.
|
public class FileManagerDirectoryContent1 : FileManagerDirectoryContent { public Dictionary<string, object> CustomData { get; set; } } … public class AzureController : Controller { public AzureFileProvider operation; public string username { get; set; } … [Route("AzureFileOperations")] public object AzureFileOperations([FromBody] FileManagerDirectoryContent1 args) { username = HttpContext.Request.Headers["Authorization"]; if (username == "Client1") { this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); this.operation.SetBlobContainer("<--blobPath1-->", "<--filePath1-->"); // Mention the path for Client 1 start_path = "<--blobPath1-->"; original_path = "<--filePath1-->"; } else { this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); this.operation.SetBlobContainer("<--blobPath2-->", "<--filePath2-->"); // Mention the path for Client 2 start_path = "<--blobPath2-->"; original_path = "<--filePath2-->"; } // Uploads the file(s) into a specified path [Route("AzureUpload")] public ActionResult AzureUpload(FileManagerDirectoryContent args) { string username = HttpContext.Request.Headers["Authorization"].ToString().Split(',')[0]; if (username == "Client1") { this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); this.operation.SetBlobContainer("<--blobPath1-->", "<--filePath1-->"); // Mention the path for user 1 start_path = "<--blobPath1-->"; original_path = "<--filePath1-->"; } else { this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); this.operation.SetBlobContainer("<--blobPath2-->", "<--filePath2-->"); // Mention the path for user 2 start_path = "<--blobPath2-->"; original_path = "<--filePath2-->"; } if (args.Path != "") { string startPath = start_path; string originalPath = (original_path).Replace(startPath, "");
args.Path = (originalPath + args.Path).Replace("//", "/"); } … } // Downloads the selected file(s) and folder(s) [Route("AzureDownload")] public object AzureDownload(string downloadInput) { FileManagerDirectoryContent1 args = JsonConvert.DeserializeObject<FileManagerDirectoryContent1>(downloadInput); username = args.customvalue; if (username == "Client1") { this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); this.operation.SetBlobContainer("<--blobPath1-->", "<--filePath1-->"); // Mention the path for user 1 start_path = "<--blobPath1-->"; original_path = "<--filePath1-->"; } else { this.operation.RegisterAzure("<--accountName-->", "<--accountKey-->", "<--blobName-->"); this.operation.SetBlobContainer("<--blobPath2-->", "<--filePath2-->"); // Mention the path for user 2 start_path = "<--blobPath2-->"; original_path = "<--filePath2-->"; } return operation.Download(args.Path, args.Names, args.Data); } |
You can use the File Manager OnSend and BeforeDownload event to send user_name from client to server. Refer to the event configurations done in the below GitHub location to understand how to send JWT token value from client to server.
https://github.com/SyncfusionExamples/blazor-filemanager-pass-jwt-token
Please try this at your end and get back to us if you need any further assistance.
Regards,
Indhumathy L
Thank you for your response. My requirement doesn't involve the user details. I just wanted to be able to supply difference containers and blob paths to the filemanager. I solved this as follows:
In program.cs I added:
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllerRoute(
name: "AzureFiles",
pattern: "FileProvider/{action}/{container}/{folder}",
defaults: new { controller = "AzureProvider" });
});
In AzureProviderController.cs
public class AzureProviderController : Controller
{
public AzureFileProvider operation;
public string blobPath { get; set; }
public string filePath { get; set; }
public string storageUrl { get; set; }
public string accountName { get; set; }
public string accountKey { get; set; }
private IConfiguration _config;
public AzureProviderController(IConfiguration configuration)
{
_config = configuration;
this.operation = new AzureFileProvider();
storageUrl = _config.GetValue<string>("AzureStorage:BaseUrl");
accountName = _config.GetValue<string>("AzureStorage:AccountName");
accountKey = _config.GetValue<string>("AzureStorage:AccountKey");
}
// [Route("AzureFileOperations")]
public object AzureFileOperations([FromBody] FileManagerDirectoryContent args, string container, string folder)
{
SetContainerAndFolder(container, folder);
public void SetContainerAndFolder(string container, string folder)
{
blobPath = $"{storageUrl}{container}";
filePath = $"{storageUrl}{container}/{folder}";
blobPath = (blobPath.Substring(blobPath.Length - 1) != "/") ? blobPath + "/" : blobPath.TrimEnd(new[] { '/', '\\' }) + "/";
filePath = (filePath.Substring(filePath.Length - 1) == "/") ? filePath.TrimEnd(new[] { '/', '\\' }) : filePath;
this.operation.SetBlobContainer(blobPath, filePath);
this.operation.RegisterAzure(accountName, accountKey, $"{container}");
}
Changed the other methods (AzureUpload, AzureDownload, AzureGetImage) to add the container and folder parameters and the call to SetContainerAndFolder from each.
Then I passed the container and folder via the SfFileManager ajax settings as follows:
<SfFileManager TValue="FileManagerDirectoryContent">
<FileManagerAjaxSettings Url="/AzureFileOperations/container/folder"
UploadUrl="/AzureUpload/container/folder"
DownloadUrl="/AzureDownload/container/folder"
GetImageUrl="/AzureGetImage/container/folder">
</FileManagerAjaxSettings>
</SfFileManager>
Where container = azure storage container and folder = path to folder
Hi Carl,
Thanks for the update.
We understand that you have achieved your requirement through your own customization. Please get back to us if you need any further assistance.
Regards,
Indhumathy L
Thank you for all your help on this.