When using ASP.NET Core, and specifying DbContext for CosmosDB with services.AddDbContext(...) in startup.cs; is it possible to configure the underlying CosmosClient to use IHttpClientFactory? Further more, is it possible to add a delegating handler to the HttpClient?
In pseudo-code it might look something like the following, albeit the following does not work:
services.AddHttpClient<CosmosClient>().AddHttpMessageHandler<CosmosManagedIdentityDelegatingHandler>();
services.AddSingleton<CosmosClient>(serviceProvider =>
{
var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
var cosmosClientOptions = new CosmosClientOptions()
{
HttpClientFactory = httpClientFactory.CreateClient
};
return new CosmosClient(connectionString, cosmosClientOptions);
});
// Here the CosmosClient defined above, using HttpClientFactory and the delegating handler,
// should be used, but in this code it isn't.
// What is missing?
services.AddDbContext<MyDbContext>(options =>
{
options.UseCosmos(endpoint, dbName);
});
With a delegating handler looking something like this:
public class CosmosManagedIdentityDelegatingHandler : DelegatingHandler
{
private readonly string[] _cosmosScope = {"https://management.azure.com/"};
private readonly TokenCredential _credential = new ChainedTokenCredential(
new ManagedIdentityCredential(),
new EnvironmentCredential());
public CosmosManagedIdentityDelegatingHandler() { }
// Handles the request for authentication token and adds it as bearer token for the outgoing request.
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var tokenRequestContext = new TokenRequestContext(_cosmosScope);
var token = await _credential.GetTokenAsync(tokenRequestContext, default);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
return await base.SendAsync(request, cancellationToken);
}
}
EF Core version:
Database provider: (e.g. Microsoft.EntityFrameworkCore.CosmosDb)
Target framework: .NET Core 3.1/ .NET 5.0)
Duplicate of #21274
Duplicate of #21274
I wonder if this would as a work-around?
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
Database.GetCosmosClient().ClientOptions.HttpClientFactory = _httpClientFactory.CreateClient;
base.OnConfiguring(optionsBuilder);
}
Update:
Didn't work, throws:
An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside 'OnConfiguring' since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
@1iveowl Closing this as a duplicate. I discussed with @AndriySvyryd, but unfortunately we don't know of a workaround at this time.
I understand.
I hope at some later point that there will be a solution. Without it I don't currently know how to utilize Azure Managed Identity with Cosmos and EF.
Utilizing HttpClientFactory seem to promis both a solution to Managed Identity as well as providing the benefits of HttpClientFactory.
Would love to work on it,but doesn't currently have the bandwidth.
@1iveowl We're planning now for EF Core 6.0. There's a very good chance that this will make it in.
Most helpful comment
@1iveowl We're planning now for EF Core 6.0. There's a very good chance that this will make it in.