如何让带宿主存储锁的Timer触发器通过IAzureClientFactory使用自定义Blob客户端?
我运行一个独立应用,使用Microsoft.Azure.WebJobs SDK,当前依赖Microsoft.Azure.WebJobs.Host.Storage(v5.0.0)和TimeTrigger。我习惯用Microsoft.Extensions.Azure集成注入Azure SDK客户端,这样能注入命名客户端并控制每个客户端使用的TokenCredential。但我发现,当尝试用注入的客户端连接宿主存储时,这个包并没有使用它,而是默认用DefaultAzureCredential(会尝试VS凭据、托管标识凭据等)。
有没有办法让Microsoft.Azure.WebJobs.Host.Storage通过注入的IAzureClientFactory解析宿主存储的Blob服务提供程序?
相关代码
Program.cs
hostBuilder.ConfigureWebJobs(serviceBuilder => { serviceBuilder.Services.AddAzureClients(builder => { builder.AddClient<BlobServiceClient, BlobClientOptions>((options, credentials, serviceProvider) => { TokenCredential tokenCredential = new MyTokenCredential(); return new BlobServiceClient(new Uri("https://<my-storage>.blob.core.windows.net"), credential: tokenCredential, options); }); }); serviceBuilder.AddAzureStorageCoreServices(); serviceBuilder.AddTimers(); });
MyTokenCredential.cs
public class MyTokenCredential : TokenCredential { public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) { Console.WriteLine("Test1"); return default; } public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) { Console.WriteLine("Test2"); return default; } }
Function.cs
public async Task Invoke5MinFlowJobsAsync([TimerTrigger("00:05:00", RunOnStartup = false)] TimerInfo timerInfo) { await _service.DoSomethingAsync("5 min"); }
appsettings.json
"AzureWebJobsStorage": { "blobServiceUri": "https://<my-storage>.blob.core.windows.net" },
要让WebJobs Host使用你注入的BlobServiceClient而非默认凭据机制,需要替换WebJobs内部的存储服务提供程序实现,具体步骤如下:
替换默认存储服务注册
不需要调用AddAzureStorageCoreServices()(或覆盖已注册的默认服务),因为它会自动注册使用DefaultAzureCredential的存储客户端。自定义Blob服务提供程序
实现IStorageBlobServiceProvider接口,从IAzureClientFactory获取你注入的客户端:public class CustomBlobServiceProvider : IStorageBlobServiceProvider { private readonly IAzureClientFactory<BlobServiceClient> _clientFactory; public CustomBlobServiceProvider(IAzureClientFactory<BlobServiceClient> clientFactory) { _clientFactory = clientFactory; } public BlobServiceClient GetBlobServiceClient(StorageAccount storageAccount) { // 直接返回注入的客户端,若需多账户可根据storageAccount信息匹配命名客户端 return _clientFactory.CreateClient(); } }注册自定义提供程序
在ConfigureWebJobs中注册你的实现,替换默认服务:hostBuilder.ConfigureWebJobs(serviceBuilder => { serviceBuilder.Services.AddAzureClients(builder => { builder.AddClient<BlobServiceClient, BlobClientOptions>((options, credentials, serviceProvider) => { TokenCredential tokenCredential = new MyTokenCredential(); return new BlobServiceClient(new Uri("https://<my-storage>.blob.core.windows.net"), tokenCredential, options); }); }); // 替换默认的Blob服务提供程序 serviceBuilder.Services.AddSingleton<IStorageBlobServiceProvider, CustomBlobServiceProvider>(); serviceBuilder.AddTimers(); });保持配置一致性
appsettings.json中的AzureWebJobsStorage配置仍需保留,WebJobs Host会读取该配置识别存储账户,但实际客户端由自定义提供程序提供。
关键说明
WebJobs SDK的存储服务默认使用内部客户端创建逻辑,不会自动从IAzureClientFactory获取实例,因此必须通过替换IStorageBlobServiceProvider来接管客户端提供逻辑。若需支持多存储账户,可在GetBlobServiceClient方法中根据传入的StorageAccount参数(如URI、名称)匹配对应的命名客户端。
内容的提问来源于stack exchange,提问作者Moti

