.NET 8 WebApi throws InvalidOperationException when keyed Services are registered before MS Identity Services are registered
thuijer opened this issue · 4 comments
Microsoft.Identity.Web Library
Microsoft.Identity.Web
Microsoft.Identity.Web version
2.15.2
Web app
Not Applicable
Web API
Not Applicable
Token cache serialization
Not Applicable
Description
In an .NET 8 ASP.NET Core WebApi, when keyed services are being added to the DI container before calling AddAuthentication(builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
, the service throws an InvalidOperationException with message "Your service provider may not support keyed services" upon startup.
Reproduction steps
- Create a standard ASP.NET Core WebAPI with auth set to Microsoft Identity Platform
- Create an empty Interface ISomeInterface :
interface ISomeInterface {}
- Create a class SomeConcreteClass that implements ISomeInterface: `class SomeConcreteClass: ISomeInterface {}
- Add
builder.Services.AddKeyedSingleton<ISomeInterface, SomeConcreteClass>("A") *BEFORE* the call to
builder.Services.AddAuthentication(builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))` - Run the application and see that it crashes
- Move the line
builder.Services.AddKeyedSingleton<ISomeInterface, SomeConcreteClass>("A")
until after thebuilder.Services.AddAuthentication()
call - Run the application and see that it starts up as expected
Error message
InvalidOperationException with message "Your service provider may not support keyed services"
at Microsoft.Extensions.DependencyInjection.ServiceDescriptor.ThrowKeyedDescriptor() in //src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs:line 1061
at Microsoft.Extensions.DependencyInjection.ServiceDescriptor.get_ImplementationType() in //src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs:line 164
at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.<>c.b__3_0(ServiceDescriptor s) in //src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs:line 151
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable1 source, Func
2 predicate, Boolean& found) in //src/libraries/System.Linq/src/System/Linq/First.cs:line 115
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 source, Func
2 predicate) in //src/libraries/System.Linq/src/System/Linq/First.cs:line 49
at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.AddMicrosoftIdentityWebApiImplementation(AuthenticationBuilder builder, Action`1 configureJwtBearerOptions, String jwtBearerScheme, Boolean subscribeToJwtBearerMiddlewareDiagnosticsEvents) in //src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs:line 151
at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.AddMicrosoftIdentityWebApi(AuthenticationBuilder builder, IConfigurationSection configurationSection, String jwtBearerScheme, Boolean subscribeToJwtBearerMiddlewareDiagnosticsEvents) in /_/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs:line 84
at Program.
Id Web logs
No response
Relevant code snippets
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// if this line is *BEFORE* the `AddAuthentication` call, the app crashes at startup
// if this line is *AFTER* the `AddAuthentication` call, the app starts up as expected
builder.Services.AddKeyedSingleton<IMyInterface, MyConcreteType>("A");
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
builder.Services.AddAuthorization();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.Run();
internal interface IMyInterface
{
}
internal class MyConcreteType : IMyInterface
{
}
Regression
No response
Expected behavior
App starts up normally
We've just hit this. Right now it prevents targeting net8.0 without workarounds, and worse - it's enough if a project references Microsoft.Extensions.DependencyInjection.Abstractions v8
(which is supported on net6 as well), so simply by a dependency update (not retargeting to new framework) it can crash.
Edit: I've raised dotnet/runtime#95789 since it seems to be a very problematic regression.
Any progress on a fix yet?
I've opened a fix PR: #2676
This should probably be released sooner rather than later...