Open Johno-ACSLive opened 1 month ago
@Johno-ACSLive would AddWebPubSub use a singleton? if that's the case you might want to move it before AddMicrosoftIdentityWebApi()
@jmprieur I'm not sure, I would assume so. Even if that were the case, why is there inconsistent bahviour? I would expect the Linux container to fail to start or log the same error when the line containing app.MapWebPubSubHub<webpubsub>("/eventhandler/{*path}");
is run.
I have the same problem when trying to inject IDownstreamApi. No registered service...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("MyApi:Settings:AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("MyApi:Settings:DownstreamApi"))
.AddInMemoryTokenCaches();
I was able to resolve my issue, and have a new one, which I'll post somewhere else later. I have a singleton service which injects my typed HttpClient
registered during startup. Within my typed HttpClient
I was injecting the IDownstreamApi and also tried the IAuthorizationHeaderProvider which also gave me this same error. The issue is that these services are all scoped and since the typed client (transient) was coming from a singleton service, I had to first create a scope as follows:
// inject IServiceProvider in constructor of the class first
using var scope = serviceProvider.CreateScope();
var downloader = scope.ServiceProvider.GetRequiredService<IDownstreamApi>();
// use interface as the docs suggest...
@jmprieur, it might be worthwhile to consider the scenario where a multi-host environment is using this MSAL library to authenticate between services; specifically when customers create their own client library. For example, the documentation to authenticate inbound public/external clients to an API is well understood. When an API needs to connect to another API, it's very common for customers to create a client library with a named or typed HttpClient
and this is where the downstream call to another API comes in. Typed http clients are transient services in .NET but these MSAL interfaces are scoped so there is definitely a case where customers could run into this issue.
Additionally, it would be helpful to have some guidance on how to handle token acquisition and renewal when fetching one manually. For example, I've noticed a typed client which has been given a token via IAuthorizationHeaderProvider.CreateAuthorizationHeaderForAppAsync()
will already have the header applied. When calling upon the typed client a second time, a check is necessary to make sure the token hasn't already been added to the authorization header.
Microsoft.Identity.Web Library
Microsoft.Identity.Web.DownstreamApi
Microsoft.Identity.Web version
2.18.1
Web app
Sign-in users and call web APIs
Web API
Protected web APIs call downstream web APIs
Token cache serialization
In-memory caches
Description
Using Microsoft Identity Abstractions version 5.3.0 via Microsoft.Identity.Web.DownstreamApi version 2.18.1, the call to
app.MapWebPubSubHub<webpubsub>("/eventhandler/{*path}");
triggers System.InvalidOperationException: 'Cannot resolve scoped service 'Microsoft.Identity.Abstractions.IDownstreamApi' from root provider.' only when debugging via Visual Studio (latest version - 17.9.6) on Windows.When run in a Linux Container the app runs fine.
I initially logged the bug in the abstractions library https://github.com/AzureAD/microsoft-identity-abstractions-for-dotnet/issues/128
Reproduction steps
Debug an ASP.NET 8.0 application using multiple IDP's and Azure Web PubSub.
Error message
System.InvalidOperationException: 'Cannot resolve scoped service 'Microsoft.Identity.Abstractions.IDownstreamApi' from root provider.'
Id Web logs
No response
Relevant code snippets
Regression
No response
Expected behavior
Error is not observed when debugging on Windows via Visual Studio.