aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

UseAuthorization does not work with WebHostBuilder on .NET 8

Open Shane32 opened this issue 1 year ago • 3 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

When using WebHostBuilder to run web applications or tests in .NET 8, and app.UseAuthorization() is called, when starting the web app, an exception is thrown stating the following:

Unable to resolve service for type 'Microsoft.AspNetCore.Routing.EndpointDataSource' while attempting to activate 'Microsoft.AspNetCore.Authorization.Policy.AuthorizationPolicyCache'.

This issue does not occur with any prior version of .NET.

Expected Behavior

Using WebHostBuilder to create a web application should work as it did in .NET 7 and prior versions.

Steps To Reproduce

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework><!-- change to 7.0 and it works -->
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
var hostBuilder = new WebHostBuilder();
hostBuilder.UseIIS(); // fails with UseKestrel() also
hostBuilder.ConfigureServices(services =>
{
    services.AddAuthentication();
    services.AddAuthorization();
});
hostBuilder.Configure(app =>
{
    app.UseAuthentication();
    app.UseAuthorization();
    app.Run(async context =>
    {
        context.Response.StatusCode = 200;
        context.Response.ContentType = "text/plain";
        await context.Response.WriteAsync("OK");
    });
});
await hostBuilder.Build().RunAsync(); // <-- crashes here

Exceptions (if any)

System.InvalidOperationException
  HResult=0x80131509
  Message=Unable to resolve service for type 'Microsoft.AspNetCore.Routing.EndpointDataSource' while attempting to activate 'Microsoft.AspNetCore.Authorization.Policy.AuthorizationPolicyCache'.
  Source=Microsoft.Extensions.DependencyInjection
  StackTrace:
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware..ctor(RequestDelegate next, IAuthorizationPolicyProvider policyProvider, IServiceProvider services)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddlewareInternal..ctor(RequestDelegate next, IServiceProvider services, IAuthorizationPolicyProvider policyProvider, ILogger`1 logger)
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) in /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs:line 178
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) in /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs:line 145
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) in /_/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs:line 162
   at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
   at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.ReflectionMiddlewareBinder.CreateMiddleware(RequestDelegate next)
   at Microsoft.AspNetCore.Builder.ApplicationBuilder.Build()
   at Microsoft.AspNetCore.Hosting.WebHost.BuildApplication() in /_/src/Hosting/Hosting/src/Internal/WebHost.cs:line 225
   at Microsoft.AspNetCore.Hosting.WebHost.<StartAsync>d__27.MoveNext() in /_/src/Hosting/Hosting/src/Internal/WebHost.cs:line 132
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__5.MoveNext() in /_/src/Hosting/Hosting/src/WebHostExtensions.cs:line 112
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__5.MoveNext() in /_/src/Hosting/Hosting/src/WebHostExtensions.cs:line 147
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__4.MoveNext() in /_/src/Hosting/Hosting/src/WebHostExtensions.cs:line 97
   at Program.<<Main>$>d__0.MoveNext() in C:\......\Program.cs:line 24
   at Program.<Main>(String[] args)

.NET Version

8.0.101

Anything else?

  • Workaround: add services.AddRouting();
  • Workaround is not required when using WebApplication.CreateBuilder

Shane32 avatar Jan 12 '24 18:01 Shane32

Hi @Shane32, I was having the same issue.

I got my tests working by adding services.AddRouting() before services.AddAuthorization().

services.AddRouting(); // <-- Order matters
services.AddAuthorization();

Background:

That idea was motivated by a comment in the source code of app.UseAuthorization().

https://github.com/dotnet/aspnetcore/blob/0bae45ebe88ad07f69e13a142c93a05b496dc9b4/src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs#L20-L21

I added the "using" (and not the service.AddRouting) and received this error:

System.InvalidOperationException: Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddRouting' inside the call to 'ConfigureServices(...)' in the application startup code.

To mitigate, I then added services.AddRouting(); before services.AddAuthorization(); and my code worked! Just out of curiosity because my tests didn't explicitly need "app.UseRouting()", I checked whether removing the "using" would render the same results. My code ran without issue.

Mitigation -> more contextual setup code.

webBuilder
    .UseTestServer()
    .ConfigureServices(services =>
    {
        services.AddAuthentication(defaultScheme: <scheme>);
        services.AddRouting();
        services.AddAuthorization();
    })
    .Configure(app =>
    {
        //app.UseRouting(); // <- didn't need this. Whether it is correct to leave out is TBD.
        app.UseAuthentication();
        app.UseAuthorization();

        // app.Run acts as terminating middleware to return 200 if we reach it. Without this,
        // the Middleware pipeline will return 404 by default.
        app.Run(async (context) =>
        {
            context.Response.StatusCode = (int)HttpStatusCode.OK;
            await context.Response.WriteAsync("Successful Request");
            await context.Response.StartAsync();
        });
    });

Original exception

I observed (and found this issue) because my stack trace matched yours.

System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Routing.EndpointDataSource' while attempting to activate 'Microsoft.AspNetCore.Authorization.Policy.AuthorizationPolicyCache'.

notes

I'm sure there must be a more elegant way of doing this, but I didn't have more time to look into this because I was trying to unblock myself from finishing a deliverable.

seantleonard avatar May 02 '24 22:05 seantleonard

I'm having this same exception, but in a console app... I added .UseRouting() and it works... but this is not a webhost?

after upgrading to NET 8

warmfire540 avatar May 06 '24 13:05 warmfire540

What warmfire said. Routing does not make sense in a Console app.

johnkors avatar Jun 27 '24 19:06 johnkors

We should optionally resolve endpoint datasource.

mikekistler avatar Nov 14 '24 17:11 mikekistler

Experiencing the same thing on a .NET 8 worker application (Microsoft.NET.Sdk.Worker) that I bootstrap with Host.CreateApplicationBuilder(). It started happening as soon as I depended on a library that has optional extension methods on WebApplicationBuilder to set up auth policies based on some incoming config.

However, I don't call that particular method. In fact, at no point is AddAuthorization() or UseAuthorization() called. Adding .AddRouting() early in my DI setup "fixed" the problem for now.

BuriedStPatrick avatar Jul 03 '25 15:07 BuriedStPatrick