自定义页面筛选器中的ASP .NET Core注入服务 - c#

我已经设置了一个过滤器来处理特定的文件夹及其中的所有页面。我需要使用声明访问数据库。问题是我似乎无法在启动服务上向DI注册过滤器,因为它找不到数据库连接

services.AddMvc()
         .AddRazorPagesOptions(options =>
         {
             options.AllowAreas = true;
             options.Conventions.AuthorizeAreaFolder("Administration", "/Account");
             options.Conventions.AuthorizeAreaFolder("Production", "/Account");
             options.Conventions.AuthorizeAreaFolder("Robotics", "/Account");
             options.Conventions.AddAreaFolderApplicationModelConvention("Production", "/FrontEnd", 
                 model => model.Filters.Add(
                     new LockdownFilter(
                         new ProducaoRegistoService(new ProductionContext()), 
                         new UrlHelperFactory(), 
                         new HttpContextAccessor())));
         })

过滤器。

public class LockdownFilter : IAsyncPageFilter
{
    private readonly IProducaoRegistoService _producaoRegistoService;
    private readonly IUrlHelperFactory _urlHelperFactory;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public LockdownFilter(IProducaoRegistoService producaoRegistoService, IUrlHelperFactory urlHelperFactory, IHttpContextAccessor httpContextAccessor)
    {
        _producaoRegistoService = producaoRegistoService;
        _urlHelperFactory = urlHelperFactory;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
    {
        int registoId;
        if(!int.TryParse(_httpContextAccessor.HttpContext.User.GetRegistoId(), out registoId))
        {
            // TODO
        }

        var registo = _producaoRegistoService.GetById(registoId);

        await next.Invoke();
    }

    public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
    {
        await Task.CompletedTask;
    }
}

错误是

InvalidOperationException:未配置数据库提供程序
为此DbContext。可以通过覆盖
DbContext.OnConfiguring方法或通过使用AddDbContext
应用程序服务提供商。如果使用AddDbContext,则也
确保您的DbContext类型接受DbContextOptions
对象在其构造函数中,并将其传递给用于
DbContext。

这是整个创业班

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {

        })
         .AddCookie("ProductionUserAuth", options =>
         {
             options.ExpireTimeSpan = TimeSpan.FromDays(1);
             options.LoginPath = new PathString("/Production/FrontEnd/Login");
             options.LogoutPath = new PathString("/Production/FrontEnd/Logout");
             options.AccessDeniedPath = new PathString("/Production/FrontEnd/AccessDenied");
             options.SlidingExpiration = true;
             options.Cookie.Name = "NoPaper.ProductionUser";
             options.Cookie.Expiration = TimeSpan.FromDays(1);
         })
             .AddCookie("ProductionAdminAuth", options =>
             {
                 options.ExpireTimeSpan = TimeSpan.FromDays(1);
                 options.LoginPath = new PathString("/Production/BackOffice/Login");
                 options.LogoutPath = new PathString("/Production/BackOffice/Logout");
                 options.AccessDeniedPath = new PathString("/Production/BackOffice/AccessDenied");
                 options.SlidingExpiration = true;
                 options.Cookie.Name = "NoPaper.ProductionAdmin";
                 options.Cookie.Expiration = TimeSpan.FromDays(1);
             })
        .AddCookie("AdministrationAuth", options =>
        {
            options.ExpireTimeSpan = TimeSpan.FromDays(1);
            options.LoginPath = new PathString("/Administration/Index");
            options.LogoutPath = new PathString("/Administration/Logout");
            options.AccessDeniedPath = new PathString("/Administration/AccessDenied");
            options.SlidingExpiration = true;
            options.Cookie.Name = "NoPaper.Administration";
            options.Cookie.Expiration = TimeSpan.FromDays(1);
        });

        services.AddAuthorization();

        services.AddMemoryCache();
        services.AddAutoMapper(typeof(Startup));

        services.AddMvc()
         .AddRazorPagesOptions(options =>
         {
             options.AllowAreas = true;
             options.Conventions.AuthorizeAreaFolder("Administration", "/Account");
             options.Conventions.AuthorizeAreaFolder("Production", "/Account");
                           options.Conventions.AddAreaFolderApplicationModelConvention("Production", "/FrontEnd", 
                 model => model.Filters.Add(
                     new LockdownFilter(
                         new ProducaoRegistoService(new ProductionContext(new DbContextOptions<ProductionContext>())), 
                         new UrlHelperFactory(), 
                         new HttpContextAccessor())));
         })
         .AddNToastNotifyToastr(new ToastrOptions()
         {
             ProgressBar = true,
             TimeOut = 3000,
             PositionClass = ToastPositions.TopFullWidth,
             PreventDuplicates = true,
             TapToDismiss = true
         })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddRouting(options =>
        {
            options.LowercaseUrls = true;
            options.LowercaseQueryStrings = true;
        });

        services.AddDbContext<DatabaseContext>(options =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), sqlServerOptionsAction: sqlOptions =>
            {
                sqlOptions.EnableRetryOnFailure(
                    maxRetryCount: 2,
                    maxRetryDelay: TimeSpan.FromSeconds(1),
                    errorNumbersToAdd: null);
                sqlOptions.MigrationsHistoryTable("hEFMigrations", "Admin");
            });
        });

        services.AddDbContext<ProductionContext>(options =>
          options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), c => c.MigrationsHistoryTable("hEFMigrations", "Admin")
     ));

        services.AddHttpContextAccessor();
        services.AddSingleton<IFileProvider>(new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/files")));
        services.AddTransient<IAuthorizationHandler, HasArranqueActivoHandler>();
        services.AddTransient<IAuthorizationHandler, HasArranqueInactivoHandler>();
        services.AddTransient<IAuthorizationHandler, IsParagemNotOnGoingHandler>();
        services.AddTransient<IAuthorizationHandler, IsParagemOnGoingHandler>();


        services.AddTransient<Services.Interfaces.IUserService, Services.UserService>();

        #region AreaProduction
        services.AddTransient<Production.Interfaces.IComponenteService, Production.ComponenteService>();
        services.AddTransient<Production.Interfaces.IReferenciaService, Production.ReferenciaService>();
        services.AddTransient<Production.Interfaces.IProducaoRegistoService, Production.ProducaoRegistoService>();
        services.AddTransient<Production.Interfaces.IParagemService, Production.ParagemService>();
        services.AddTransient<Production.Interfaces.ICelulaService, Production.CelulaService>();
        services.AddTransient<Production.Interfaces.IUapService, Production.UapService>();
        services.AddTransient<Production.Interfaces.ICelulaTipoService, CelulaTipoService>();
        services.AddTransient<Production.Interfaces.IMatrizService, MatrizService>();
        services.AddTransient<Production.Interfaces.IOperadorService, Production.OperadorService>();
        services.AddTransient<Production.Interfaces.IEtiquetaService, Production.EtiquetaService>();
        services.AddTransient<Production.Interfaces.IPokayokeService, Production.PokayokeService>();
        services.AddTransient<Production.Interfaces.IGeometriaService, Production.GeometriaService>();
        services.AddTransient<Production.Interfaces.IEmpregadoService, Production.EmpregadoService>();
        services.AddTransient<Production.Interfaces.IPecaService, Production.PecaService>();
        services.AddTransient<Production.Interfaces.IDefeitoService, Production.DefeitoService>();
        services.AddTransient<Production.Interfaces.ITurnoService, Production.TurnoService>();
        #endregion


    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(errorApp =>
            {
                errorApp.Run(async context =>
                {
                    var exceptionHandlerPathFeature =
                        context.Features.Get<IExceptionHandlerPathFeature>();

                    // Use exceptionHandlerPathFeature to process the exception (for example, 
                    // logging), but do NOT expose sensitive error information directly to 
                    // the client.

                    if (exceptionHandlerPathFeature.Path.Contains("/Administration/") ||
                        exceptionHandlerPathFeature.Path.Contains("/administration/"))
                    {
                        context.Response.Redirect("/Administration/Error");
                    }

                    if (exceptionHandlerPathFeature.Path.Contains("/Production/") ||
                        exceptionHandlerPathFeature.Path.Contains("/production/"))
                    {
                        context.Response.Redirect("/Production/Error");
                    }
                });
            });
        }

        app.UseNToastNotify();
        app.UseAuthentication();

        app.UseStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
            name: "areas",
            template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
          );

            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

我的背景

 public class ProductionContext : DbContext
{
    //static LoggerFactory object
    public static readonly ILoggerFactory loggerFactory = new LoggerFactory(new[] {
          new ConsoleLoggerProvider((_, __) => true, true)
    });

    public ProductionContext()
    {

    }

    public ProductionContext(DbContextOptions<ProductionContext> options) : base(options)
    {

    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLoggerFactory(loggerFactory)  //tie-up DbContext with LoggerFactory object
            .EnableSensitiveDataLogging();
    }
 ...
}

参考方案

您的问题中有很多代码,因此我将首先强调感兴趣的代码:

options.Conventions.AddAreaFolderApplicationModelConvention("Production", "/FrontEnd", 
    model => model.Filters.Add(
        new LockdownFilter(
            new ProducaoRegistoService(new ProductionContext()), 
            new UrlHelperFactory(), 
            new HttpContextAccessor())));

现在,让我们再看看错误消息:

InvalidOperationException:没有为此DbContext配置数据库提供程序。可以通过重写DbContext.OnConfiguring方法或在应用程序服务提供程序上使用AddDbContext来配置提供程序。如果使用AddDbContext,则还要确保您的DbContext类型在其构造函数中接受DbContextOptions对象,并将其传递给DbContext的基本构造函数。

在您的情况下,未配置在我调出的代码中创建的ProductionContext实例。您可能会认为正在配置它是因为您在AddDbContext方法中的其他地方使用了ConfigureServices的方式,但事实并非如此。

AddDbContext设置DI所需的一切,以便为您提供根据您的设置配置的ProductionContext实例(使用带有DefaultConnection连接字符串的SQL Server)。但是,通过创建您自己的ProductionContext实例并将其传递给过滤器,根本不会使用DI配置的实例。

一个明显的解决方案是将DI用于这些服务,但这并不是那么简单,因为在创建LockdownFilter实例时您无权访问DI。这是TypeFilterAttributeServiceFilterAttribute的来源,在Filters in ASP.NET Core: Dependency injection中有充分的文档说明。这是我调用的代码的更新版本,它使用TypeFilterAttribute

options.Conventions.AddAreaFolderApplicationModelConvention("Production", "/FrontEnd", 
    model => model.Filters.Add(new TypeFilterAttribute(typeof(LockdownFilter))));

使用这种方法,传递给您的LockdownFilter构造函数的参数将通过DI进行解析。从您的问题中可以很明显地看出,这三个服务都已在DI容器中注册,因此应该可以正常使用。

jQuery发布不会将数据发布到ASP.NET API控制器 - javascript

我有一次噩梦般的时间通过jquery post将数据发送到ASP.NET Controller。这是JSON.stringify之后的数据:[{"scheduleTaskID":"203","task":"Permit","baselineDate":…

使用Java脚本基于另一个控件项来验证ASP.NET C#控件 - c#

我正在尝试确保一个下拉框或另一个下拉框具有选定的条目,不能两者都选,并且不能都留空/未选择。每次单击运行javascript验证代码的搜索按钮时,即使我只是从一个下拉列表中选择,甚至从两个下拉列表中都没有选择,我都会收到一条消息,好像在两个下拉框中都选择了一样!这可能是我的逻辑,但是,我认为也可能是我的变量读为null。是否有人对问题可能是什么以及如何解决这…

将asp.net.core 2.0应用发布到IIS时JavaScript无法运行 - javascript

我是这里的新手。我有一个VS2017 asp.net C#Web应用程序。我目前不在使用Angular。这是一个简单的网站。我隐藏了div,当用户单击菜单项时,相关的div出现,而我隐藏了其余的div。我使用JavaScript完成此任务。在开发和IIS Express中,它可以工作。当我发布到IIS时,它不起作用。静态页面显示“确定”,但菜单按钮不执行任何…

ASP.net C#崩溃一行 - c#

我有一个母版页,在on load事件中包含以下几行: string menuIDdata = Page.Request.QueryString["mid"]; menuID = 0; // Get the menu ID if (!int.TryParse(menuIDdata, out menuID)) { menuID = 0; } …

如果数字是1或0,则显示不同的图标-ASP.NET C#MVC JQuery - javascript

我有一个生成随机数的模型:public int IsLocked { get { var rnd = new Random(); return rnd.Next(0, 2); } } 这是我的局部视图:<table class="table table-striped table-hover dataTable admin-form them…