依赖注入:对接多Azure存储实例如何避免重复定义接口与实现类?
多Azure Blob Storage实例接入优化方案
1. 复用统一接口与实现
删除所有带数字后缀的重复接口、实现类,仅保留一套通用定义:
通用接口定义
public interface IAzureBlobStorage { string AzureBlobContainerName { get; } string StorageName { get; } public Task<Stream> DownloadStreamAsyns(string fileName); public Task Upload(string fileId, Stream stream); }
通用实现类定义
public class AzureBlobStorage : IAzureBlobStorage { private BlobContainerClient _client; private string _containerName; private string _storageName; public string StorageName => _storageName; public string AzureBlobContainerName => _containerName; public AzureBlobStorage(BlobContainerClient client, string containerName, string storageName) { _client = client; _containerName = containerName; _storageName = storageName; } public async Task<Stream> DownloadStreamAsyns(string fileName) { return await _client.GetBlobClient(fileName).OpenReadAsync(); } public async Task Upload(string fileId, Stream stream) { await _client.GetBlobClient(fileId).UploadAsync(stream); } }
2. 通用服务注册
方案A:.NET 8+ 键控服务(推荐)
.NET 8开始原生支持按键注入服务,不用额外实现工厂:
编写自动注册扩展方法
public static IServiceCollection AddAllAzureStorages(this IServiceCollection services, IConfiguration configuration) { // 读取所有存储配置节点 var storageSections = configuration.GetSection("AzureBlobStorageConfiguration:Storages").GetChildren(); foreach (var section in storageSections) { var options = new ABlobStorageConfigurationOptionsDTO(); section.Bind(options); // 以存储配置的节点名(Storage1/Storage2/Storage3)作为键注册服务 services.AddKeyedTransient<IAzureBlobStorage, AzureBlobStorage>(section.Key, (isp, _) => { var client = new BlobServiceClient(options.ConnString); var container = client.GetBlobContainerClient(options.AzureBlobContainerName); return new AzureBlobStorage(container, options.AzureBlobContainerName, options.StorageName); }); } return services; }
启动类中调用注册
在Startup.cs/Program.cs中只需调用一次即可注册所有配置的存储实例:
services.AddAllAzureStorages(configuration);
业务中注入使用
在控制器/服务中按存储名注入对应实例即可:
public class YourController : Controller { private readonly IAzureBlobStorage _storage1; private readonly IAzureBlobStorage _storage2; public YourController( [FromKeyedServices("Storage1")] IAzureBlobStorage storage1, [FromKeyedServices("Storage2")] IAzureBlobStorage storage2) { _storage1 = storage1; _storage2 = storage2; } }
方案B:.NET 7及以下版本 工厂模式
如果使用不支持键控服务的低版本.NET,可通过工厂类实现实例获取:
定义存储工厂
public interface IAzureBlobStorageFactory { IAzureBlobStorage GetStorage(string storageName); } public class AzureBlobStorageFactory : IAzureBlobStorageFactory { private readonly IConfiguration _configuration; public AzureBlobStorageFactory(IConfiguration configuration) { _configuration = configuration; } public IAzureBlobStorage GetStorage(string storageName) { var options = new ABlobStorageConfigurationOptionsDTO(); _configuration.GetSection($"AzureBlobStorageConfiguration:Storages:{storageName}").Bind(options); var client = new BlobServiceClient(options.ConnString); var container = client.GetBlobContainerClient(options.AzureBlobContainerName); return new AzureBlobStorage(container, options.AzureBlobContainerName, options.StorageName); } }
注册工厂
services.AddSingleton<IAzureBlobStorageFactory, AzureBlobStorageFactory>();
业务中使用
public class YourController : Controller { private readonly IAzureBlobStorage _storage1; private readonly IAzureBlobStorage _storage2; public YourController(IAzureBlobStorageFactory storageFactory) { _storage1 = storageFactory.GetStorage("Storage1"); _storage2 = storageFactory.GetStorage("Storage2"); } }
优化后效果
- 新增存储实例仅需在
appsettings.json中添加对应配置节点,无需新增任何接口、实现类和注册代码 - 完全消除重复代码,后续调整存储通用逻辑仅需修改一次
- 存储数量无上限,可根据配置灵活扩展
内容的提问来源于stack exchange,提问作者jrywin
相关产品推荐
相关产品推荐

