Search code examples
asp.net-corerazorazure-storagerazor-pagesazure-storage-files

Azure Storage FileShare with ASP.Net Core and Razor Page


Beginner question

I am using the latest ASP.NET Core SDK to build an MVC/Razor page to display user files. We have the files in Azure Storage FileShare. The difficulty I'm running into is getting the FILES to list out and there is very little documentation on how to do this out there. Once I finally get it figured out I would like to create a post on Medium or somewhere else to help any other beginners.

The file structure of the File Share is as such:

Azure File Share
  MainShare
    EmployeNumber
      Folder1
        files.pdf
      Folder2
        files.pdf
      Folder3
        files.pdf

I have been able to successfully get blob information to display since that's the bulk of information out there, but I'm having trouble FileShare to display anything.

At first, I was running into an invalid cast issue where it was trying to cast CloudFileDirectory on my CloudFile so I found a solution to help it determine what to cast where. Now the page will attempt to run but nothing is produced and the page just loads and loads.

FileController.cs

public async Task<IActionResult> Index()
        {
            string filestorageconnection = _configuration.GetValue<string>("filestorage");
            CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(filestorageconnection);

            //CloudFile cloudFile = null;
            
            CloudFileShare fileShare = null;

            CloudFileClient cloudFileClient = cloudStorageAccount.CreateCloudFileClient();

            fileShare = cloudFileClient.GetShareReference("MainShare");
            

            List<IListFileItem> shareData = new List<IListFileItem>();
            List<FileShareData> fileData = new List<FileShareData>();

            FileContinuationToken token = null;
            do
            {
                FileResultSegment resultSegment =
                    await fileShare.GetRootDirectoryReference().ListFilesAndDirectoriesSegmentedAsync(token);

                foreach (var fileItem in resultSegment.Results)
                {
                    if (fileItem is CloudFile)
                    {
                        var cloudFile = (CloudFile) fileItem;
                        //await cloudFile.FetchAttributesAsync();   <--- Not sure this does what i'm looking for
                        
                        // Add properties to FileShareData List
                        fileData.Add(new FileShareData()
                        {
                            FileName = cloudFile.Name,
                            LastModified = DateTime.Parse(cloudFile.Properties.LastModified.ToString()).ToLocalTime().ToString(),
                            Size = Math.Round((cloudFile.Properties.Length / 1024f) / 1024f, 2).ToString()
                        });
                    }
                    else if (fileItem is CloudFileDirectory)
                    {
                        var cloudFileDirectory = (CloudFileDirectory) fileItem;
                        await cloudFileDirectory.FetchAttributesAsync();
                    }
                }
            } while (token != null);

            return View(fileData);  
        }

FileShareData.cs

namespace FileShareMVC.Models
{
    public class FileShareData
    {
        public string FileName { get; set; }
        public string LastModified { get; set; }
        public string Size { get; set; }
    }
}

ShowAllFiles.cshtml

@model List<FileShareData>
@{
    ViewData["Title"] = "ShowAllFiles";
}

<h1>ShowAllBlobs</h1>
<table class="table table-bordered">
    <thead>
    <tr>
        <th>FileName</th>
        <th>FileSize</th>
        <th>ModifiedOn</th>
        <th>Download</th>
    </tr>
    </thead>
    <tbody>
    @foreach (var data in Model)
    {
        <tr>
            <td>@data.FileName</td>
            <td>@data.Size</td>
            <td>@data.LastModified</td>
            <td> <a href="/File/[email protected]">Download</a> </td>
        </tr>
    }
    </tbody>
</table>

I'm not sure where to set a breakpoint to see whats stalling where. I've looked at the Network files in chrome when loading the page but nothing populates either.

Suggestions?


Solution

  • Regarding how to list all files in one Azure file share with method ListFilesAndDirectoriesSegmentedAsync, please refer to the following code

    The file structure of the File Share is as such:

    Azure File Share
      MainShare
         mydirectory
          logs
            STATS.LOG        
          csv
            test.csv
          cert
            examplecert.pfx
    

    The SDK I use

    <PackageReference Include="Microsoft.Azure.Storage.File" Version="11.1.7" />
    

    Code

    • FileController.cs
    public class FileController : Controller
        {
            public async Task<IActionResult> Index()
            {
                string accountName = "blobstorage0516";
                string key = "eGier5YJBzr5z3xgOJUb+snTGDKhwPBJRFqb2nL5lcacmKZXHgY+LjmYapIHL7Csvgx75NwiOZE7kYLJfLqWBg==";
                var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, key), true);
                var share = storageAccount.CreateCloudFileClient().GetShareReference("mainshare");
                var dir =share.GetRootDirectoryReference();
                //list all files in the directory
                var fileData = await list_subdir(dir);
                return View(fileData);
            }
    
    
    
            private static async Task<List<FileShareData>> list_subdir(CloudFileDirectory fileDirectory)
            {
                var fileData = new List<FileShareData>();
                FileContinuationToken token = null;
                do
                {
                    FileResultSegment resultSegment = await fileDirectory.ListFilesAndDirectoriesSegmentedAsync(token);
                    foreach (var fileItem in resultSegment.Results) {
    
                        if (fileItem is CloudFile) {
                            var cloudFile = (CloudFile)fileItem;
                            //get the cloudfile's propertities and metadata 
                            await cloudFile.FetchAttributesAsync();  
    
                            // Add properties to FileShareData List
                            fileData.Add(new FileShareData()
                            {
                                FileName = cloudFile.Name,
                                LastModified = DateTime.Parse(cloudFile.Properties.LastModified.ToString()).ToLocalTime().ToString(),
                                // get file size as kb
                                Size = Math.Round((cloudFile.Properties.Length / 1024f), 2).ToString()
                            });
    
                        }
    
                        if (fileItem is CloudFileDirectory)
                        {
                            var cloudFileDirectory = (CloudFileDirectory)fileItem;
                            await cloudFileDirectory.FetchAttributesAsync();
    
                            //list files in the directory
                            var result = await list_subdir(cloudFileDirectory);
                            fileData.AddRange(result);
                        }
                    }
                    // get the FileContinuationToken to check if we need to stop the loop
                    token = resultSegment.ContinuationToken;
                }
                while (token != null);
    
                return fileData;
                
    
            }
        }
    
    • FileShareData.cs
    public class FileShareData
        {
            public string FileName { get; set; }
            public string LastModified { get; set; }
            public string Size { get; set; }
        }
    
    • ShowAllFiles.cshtml
    @model List<FileShareData>
    @{
        ViewData["Title"] = "ShowAllFiles";
    }
    
    <h1>ShowAllBlobs</h1>
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>FileName</th>
            <th>FileSize</th>
            <th>ModifiedOn</th>
            <th>Download</th>
        </tr>
        </thead>
        <tbody>
        @foreach (var data in Model)
        {
            <tr>
                <td>@data.FileName</td>
                <td>@data.Size</td>
                <td>@data.LastModified</td>
                <td> <a href="/File/[email protected]">Download</a> </td>
            </tr>
        }
        </tbody>
    </table>
    

    Result enter image description here

    For more details, please refer to here and here