gpt4 book ai didi

c# - 自定义页面过滤器中的 ASP .NET Core 注入(inject)服务

转载 作者:行者123 更新时间:2023-12-01 22:36:49 25 4
gpt4 key购买 nike

我设置了一个过滤器来处理特定文件夹及其内的所有页面。我需要使用声明访问数据库。问题是我似乎无法在启动服务上向 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: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for 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: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.

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

AddDbContext 设置 DI 所需的一切,为您提供一个 ProductionContext 实例,该实例根据您的设置进行配置(使用 SQL Server 和 DefaultConnection 连接字符串)。但是,通过创建您自己的 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 容器中注册,因此应该按原样工作。

关于c# - 自定义页面过滤器中的 ASP .NET Core 注入(inject)服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57539964/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com