You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否通过Blazor Server应用(C#)直接从Azure Storage提供文件夹实体?

实现Azure Storage文件夹作为单个实体在Blazor Server中提供静态文件服务

完全可以实现,无需下载文件夹到本地、本地枚举文件或压缩,直接通过Azure Storage的API结合Blazor Server的自定义逻辑完成。以下是两种可行方案:

方案一:自定义静态文件提供器(模拟本地静态目录体验)

通过实现IFileProvider接口,将Azure Storage中的指定前缀(模拟文件夹)映射为Blazor Server的静态资源路径,让用户可以像访问本地静态文件一样访问Azure Storage里的内容。

步骤1:安装依赖

安装Azure.Storage.Blobs NuGet包,用于操作Azure Storage Blob。

步骤2:实现自定义文件提供器

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Microsoft.Extensions.FileProviders;
using System.IO;

public class AzureBlobFileProvider : IFileProvider
{
    private readonly BlobContainerClient _containerClient;
    private readonly string _basePrefix;

    public AzureBlobFileProvider(BlobContainerClient containerClient, string basePrefix)
    {
        _containerClient = containerClient;
        _basePrefix = basePrefix.TrimEnd('/') + '/';
    }

    public IDirectoryContents GetDirectoryContents(string subpath)
    {
        var fullPrefix = string.IsNullOrEmpty(subpath) ? _basePrefix : $"{_basePrefix}{subpath.TrimStart('/')}/";
        var blobs = _containerClient.GetBlobsAsync(prefix: fullPrefix)
                                    .Result
                                    .Select(b => new AzureBlobFileInfo(_containerClient.GetBlobClient(b.Name), b))
                                    .ToList();
        return new EnumerableDirectoryContents(blobs);
    }

    public IFileInfo GetFileInfo(string subpath)
    {
        var blobPath = $"{_basePrefix}{subpath.TrimStart('/')}";
        var blobClient = _containerClient.GetBlobClient(blobPath);
        if (blobClient.Exists().Result)
        {
            var blobProps = blobClient.GetProperties().Result;
            return new AzureBlobFileInfo(blobClient, blobProps);
        }
        return new NotFoundFileInfo(subpath);
    }

    public IChangeToken Watch(string filter) => NullChangeToken.Singleton;
}

public class AzureBlobFileInfo : IFileInfo
{
    private readonly BlobClient _blobClient;
    private readonly BlobProperties _properties;

    public AzureBlobFileInfo(BlobClient blobClient, BlobItem blobItem)
    {
        _blobClient = blobClient;
        _properties = blobClient.GetProperties().Result;
    }

    public AzureBlobFileInfo(BlobClient blobClient, BlobProperties properties)
    {
        _blobClient = blobClient;
        _properties = properties;
    }

    public bool Exists => true;
    public long Length => _properties.ContentLength;
    public string PhysicalPath => null;
    public string Name => _blobClient.Name.Split('/').Last();
    public DateTimeOffset LastModified => _properties.LastModified;
    public bool IsDirectory => _blobClient.Name.EndsWith('/');

    public Stream CreateReadStream()
    {
        return _blobClient.OpenReadAsync().Result;
    }
}

步骤3:配置Blazor Server

在Program.cs中注册容器客户端和自定义文件提供器,配置静态文件中间件:

var builder = WebApplication.CreateBuilder(args);

// 初始化Azure Blob容器客户端
var storageConnString = builder.Configuration.GetConnectionString("AzureStorage");
var containerClient = new BlobContainerClient(storageConnString, "your-container-name");
containerClient.CreateIfNotExists();

// 注册自定义文件提供器,映射到目标文件夹前缀
builder.Services.AddSingleton<IFileProvider>(new AzureBlobFileProvider(containerClient, "your-target-folder/"));

// 添加Blazor服务
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

var app = builder.Build();

// 配置静态文件中间件,指定访问路径
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = app.Services.GetRequiredService<IFileProvider>(),
    RequestPath = "/azure-static" // 用户访问路径示例:https://yourapp.azure-static/index.html
});

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

方案二:Blazor组件+API端点(自定义文件夹浏览与文件传输)

通过Blazor组件展示Azure Storage文件夹内的文件列表,配合API端点直接流式返回Blob内容,完全避免本地存储操作。

步骤1:注册Blob容器客户端

在Program.cs中添加:

builder.Services.AddSingleton(x => 
    new BlobContainerClient(builder.Configuration.GetConnectionString("AzureStorage"), "your-container-name"));

步骤2:创建文件夹浏览组件

@page "/azure-folder/{folderPath}"
@inject BlobContainerClient ContainerClient

<h3>Folder: @folderPath</h3>

@if (blobs != null)
{
    <ul>
        @foreach (var blob in blobs)
        {
            <li>
                <a href="@($"api/azure-file/{Uri.EscapeDataString(blob.Name)}")">@blob.Name.Split('/').Last()</a>
            </li>
        }
    </ul>
}

@code {
    [Parameter]
    public string folderPath { get; set; }

    private List<BlobItem> blobs;

    protected override async Task OnInitializedAsync()
    {
        var prefix = $"{folderPath.TrimEnd('/')}/";
        blobs = await ContainerClient.GetBlobsAsync(prefix: prefix).ToListAsync();
    }
}

步骤3:创建文件传输API端点

using Azure.Storage.Blobs;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/azure-file")]
public class AzureFileController : ControllerBase
{
    private readonly BlobContainerClient _containerClient;

    public AzureFileController(BlobContainerClient containerClient)
    {
        _containerClient = containerClient;
    }

    [HttpGet("{blobPath}")]
    public async Task<IActionResult> GetFile(string blobPath)
    {
        var decodedPath = Uri.UnescapeDataString(blobPath);
        var blobClient = _containerClient.GetBlobClient(decodedPath);
        
        if (!await blobClient.ExistsAsync())
        {
            return NotFound();
        }

        var properties = await blobClient.GetPropertiesAsync();
        var stream = await blobClient.OpenReadAsync();

        return File(stream, properties.Value.ContentType, Path.GetFileName(decodedPath));
    }
}

注意事项

  • 权限配置:如果容器是私有访问,确保Blazor Server应用拥有足够的权限(可使用Azure Managed Identity或连接字符串)。
  • 性能优化:Blob查询结果可适当缓存,避免频繁调用Azure Storage API。
  • 大文件处理:流式返回时无需将文件加载到内存,避免内存溢出问题。

内容的提问来源于stack exchange,提问作者MD Hava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:08:11