尝试将db上下文注入自定义中间件时获取InvalidOperationException

时间:2018-01-30 21:57:45

标签: c# asp.net-core asp.net-core-mvc

我需要将一个db上下文对象注入一个名为 AuthenticateClient 的自定义中间件,但是我得到了异常:

  

InvalidOperationException:无法解析作用域服务   ' LC.Tools.API.Data.ApiDbContext'来自root provider。

AuthenticateClient.cs

public class AuthenticateClient
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
    private readonly GenericUnitOfWork _worker;

    public AuthenticateClient(RequestDelegate next, ApiDbContext db, IHttpContextAccessor httpContext, IHostingEnvironment env, ILoggerFactory loggerFactory, IOptions<Utility.LCLog.Settings> settings)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger(settings.Value.ApplicationName);
        _worker = new GenericUnitOfWork(new AppHelper(httpContext, db, env));
    }

    public async Task Invoke(HttpContext context)
    {
        if (!context.Request.Headers.Keys.Contains("key") || !context.Request.Headers.Keys.Contains("pass"))
        {
            context.Response.StatusCode = 400;
            await context.Response.WriteAsync("Key or Pass missing from request header values");

            return;
        }
        else
        {
            Client client;
            string key, pass;

            key = context.Request.Headers["key"];
            pass = context.Request.Headers["pass"];

            client = await _worker.GetRepo<Client>().SingleOrDefault(clnt => clnt.Active && clnt.Key.Equals(key) && clnt.Password.Equals(pass));

            if (client == null)
            {
                _logger.LogWarning("Client authentication failed", new string[] { "Key: " + key, "Password: " + pass, "Host: " + context.Request.Host });

                context.Response.StatusCode = 401;
                await context.Response.WriteAsync("Authentication failed");

                return;
            }
        }

        await _next.Invoke(context);
    }
}

AuthenticateClientExtension.cs

public static class AuthenticateClientExtension
{
    public static IApplicationBuilder UseClientAuthentication(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<AuthenticateClient>();
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApiDbContext>(options => options.UseSqlServer(this.ConnectionString));

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IOptions<Settings> lclog)
{
    loggerFactory.AddLCLog(lclog.Value);

    app.UseClientAuthentication();
    app.UseMvc();
}

ApiDbContext.cs

public class ApiDbContext : DbContext, IApiDbContext
{
    public ApiDbContext(DbContextOptions<ApiDbContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        ...
    }
}

1 个答案:

答案 0 :(得分:2)

  

解决方案是使用 IApplicationBuilder 创建范围和init    ApiDbContext 并将其传递给中间件对象。我还改变了注册 ApiDbContext

的方式

<强> AuthenticateClientExtension.cs

public static class AuthenticateClientExtension
{
    public static IApplicationBuilder UseClientAuthentication(this IApplicationBuilder builder)
    {
        var scope = builder.ApplicationServices.CreateScope();
        ApiDbContext db = scope.ServiceProvider.GetRequiredService<ApiDbContext>();

        return builder.UseMiddleware<AuthenticateClient>(db);
    }
}

<强> Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApiDbContext>(options => options.UseSqlServer(this.ConnectionString));

    ...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IOptions<Settings> lclog)
{
    ...

    app.UseClientAuthentication();
    app.UseMvc();
}