[FEATURE REQ] Support keyed DI with AddAzureClients
Library name
Microsoft.Extensions.Azure
Please describe the feature.
When registering multiple services by name (using WithName()) with .AddAzureClients, you need to resolve the intended service via DI by injecting an IAzureClientFactory<TClient> so that you can invoke .CreateClient() on the named service.
It would be great if registering a dependency by name would register the client with the new keyed DI support so that instances of TClient can be injected directly. Or if that poses compatibility issues, add a new WithKey() method to do the same.
Thank you for your feedback, @Arithmomaniac. We've added this to our backlog for consideration.
@AlexanderSher: Would you please take a look at whether it is feasible to support the new keyed DI registration without breaking changes and advise?
Hi @Arithmomaniac. Thank you for opening this issue and giving us the opportunity to assist. To help our team better understand your issue and the details of your scenario please provide a response to the question asked above or the information requested above. This will help us more accurately address your issue.
@Arithmomaniac -- thanks for your feature request! As we look further into different approaches to enabling your scenario, it would be helpful for us to have a clear picture in our heads of what you'd like to do with keyed DI registration. Would it be possible to give us a sense of the type of app that you're building around the DI container and what scenarios/features you are looking to implement that you are unable to accomplish today without keyed registration support? Many thanks in advance for your help on this!
I've moved on to other projects, but IIRC the use case was pretty similar to the one provided in the DI documentation. Suppose the following DI configuration:
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("PublicStorage"));
.WithName("PublicStorage");
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("PrivateStorage"))
.WithName("PrivateStorage");
});
Today you have to do the following:
public class HomeController : Controller
{
private readonly ICache _bigCache;
private readonly BlobServiceClient _publicStorage;
private readonly BlobServiceClient _privateStorage;
public HomeController(
[FromKeyedServices("big")] ICache bigCache,
IAzureClientFactory<BlobServiceClient> clientFactory)
{
_bigCache = bigCache;
_publicStorage = clientFactory.CreateClient("PublicStorage");
_privateStorage = clientFactory.CreateClient("PrivateStorage");
}
}
I'd like to be able to do the following:
public class HomeController(
[FromKeyedServices("big")] ICache bigCache,
[FromKeyedServices("PublicStorage")] BlobServiceClient publicStorage,
[FromKeyedServices("PrivateStorage")] BlobServiceClient privateStorage
) : Controller
{
}
Advantages:
- Makes it easier to pass in test doubles during testing - don't need to mock a whole client factory to return two concrete instances
- Makes it easier to use primary constructors (as shown)
- Unified, idiomatic interface for "keying" Azure and non-Azure services
Thank you so much for the explanation, @Arithmomaniac!
Just to confirm that I am understanding correctly -- Microsoft.Extensions.Azure APIs strictly-speaking support the scenario you're interested in (adding multiple instances of a single client type to the DI service collection) via the WithName extension method. But, if we were to better integrate it with the new-in-.NET8 keyed services feature, it would have the advantages you listed as a result of better ecosystem integration. Specifically, you could then make one or more keyed services (e.g. Azure.Storage.Blobs.BlobServiceClient instances) parameters to an ASP.NET controller, which would retrieve the client(s) from the DI service collection rather than requiring you to create them new via the call to the Azure client factory.
Is that correct?
Hi @Arithmomaniac. Thank you for opening this issue and giving us the opportunity to assist. To help our team better understand your issue and the details of your scenario please provide a response to the question asked above or the information requested above. This will help us more accurately address your issue.
Precisely
Looking at this as part of https://github.com/Azure/azure-sdk-for-net/issues/46671
+1 for supporting keyed service by AddAzureClients et al
While waiting for official support, here's how you can achieve the same. Instead of calling WithName, you'd call WithKey.
public static class AzureClientBuilderExtensions
{
public static IAzureClientBuilder<TClient, TOptions> WithKey<TClient, TOptions>(
this IAzureClientBuilder<TClient, TOptions> builder, string serviceKey)
where TOptions : class where TClient : class
{
builder.WithName(serviceKey);
var services = (IServiceCollection)builder.GetType().GetProperty("ServiceCollection")!.GetValue(builder)!;
services.AddKeyedSingleton<TClient>(serviceKey,
(provider, _) => provider.GetRequiredService<IAzureClientFactory<TClient>>().CreateClient(serviceKey));
return builder;
}
}
This would be great to have!
Slightly related question:
Any suggestions when you have many (storage account per customer) BlobServiceClients? Adding it with the customer key WithKey or WithName isn't possible because new customer storage accounts are then not added to the DI container.
I personally think creating a client per request and disposing it is the only solution.
any updates on this request? It would be super useful for aspire integration.
Handy feature. It should allow for the reduction of boilerplate code.
Hi @Arithmomaniac, we deeply appreciate your input into this project. Regrettably, this issue has remained unresolved for over 2 years and inactive for 30 days, leading us to the decision to close it. We've implemented this policy to maintain the relevance of our issue queue and facilitate easier navigation for new contributors. If you still believe this topic requires attention, please feel free to create a new issue, referencing this one. Thank you for your understanding and ongoing support.
hi @jsquire, would this be something the team could take a look and comment? and ideally reopen too
@abatishchev: The Microsoft.Extensions.Azure package is an implementation based on legacy patterns in the .NET ecosystem and is not receiving further improvements at this point. Work is in progress to build modern support for dependency injection, configuration, and options integration directly into the Azure clients rather than requiring an additional bridge package.
While there are no formal tracking items and the shape of the API is still being refined, we expect this to land early in 2026. The draft where the work is happening is #53527.