4

I need to use entity framework in my custom authorization handler. But it's not working. It fails on runtime. I am getting this error in response body:

<h2 class="stackerror">InvalidOperationException: Cannot consume scoped service &#x27;SomeDbContext&#x27; from singleton &#x27;Microsoft.AspNetCore.Authorization.IAuthorizationHandler&#x27;.</h2>

I can't inject DB Context like this. How can I use db context in my custom authorization handler?

In my custom authorization handler class:

public class CustomAuthorizationHandler : AuthorizationHandler<CustomAuthRequirement>
{
    private readonly SomeDbContext _dbContext;

    public CustomAuthorizationHandler(SomeDbContext context)
    {
        _dbContext = context;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomAuthRequirement requirement)
    {
        ...

        //Some datatable read operations with _dbContext

        ...
    }
}

In my Startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<SomeDbContext>(options =>
              options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));

        services.AddSingleton<IAuthorizationPolicyProvider, CustomAuthPolicyProvider>();

        services.AddSingleton<IAuthorizationHandler, CustomAuthorizationHandler>();

        ...
    }
Nkosi
  • 235,767
  • 35
  • 427
  • 472
Furkan Kara
  • 349
  • 2
  • 14

2 Answers2

7

You could just inject IServiceProvider serviceProvider into the CustomAuthorizationHandler .Try to use below code:

public class CustomAuthorizationHandler : AuthorizationHandler<CustomAuthRequirement>
{
    private readonly IServiceProvider _serviceProvider;

    public CustomAuthorizationHandler (IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   CustomAuthRequirement requirement)
    {

        using (var scope = _serviceProvider.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetRequiredService<SomeDbContext>();

            //...
        }
    }
}
Ryan
  • 19,118
  • 10
  • 37
  • 53
  • 1
    It works. Thanks. I use ``IServiceScopeFactory.CreateScope()`` instead of ``IServiceProvider.CreateScope()``. Both are the same thing I think. – Furkan Kara Oct 09 '19 at 14:46
0

I had the same problem, it turned out all i needed to change was the scope, on startup if you do

services.AddTransient<IAuthorizationHandler, CustomAuthorizationHandler>();

it will probably fix it like it fixed my code, and that way i didn't need to add any extra code

RagnaRock
  • 2,432
  • 7
  • 34
  • 56
  • EF core does not support explicit concurrent use from multiple threads. There is a small use case where transient is acceptable but not in your use case. you use should AddScoped instead. https://stackoverflow.com/questions/67206763/when-to-use-following-transient-scoped-and-singleton – THE AMAZING Feb 25 '23 at 23:06