ASP.NET Core 6:如何在IPageFilter中注入ApplicationDbContext
ASP.NET Core 6中Razor页面带依赖注入的IPageFilter实现问题
问题场景
在ASP.NET Core 6中为Razor页面实现IPageFilter时,需要使用DI容器中注册的ApplicationDbContext,但在页面上添加过滤器特性时出现错误:
没有与“CustomPageFilterAttribute.CustomPageFilterAttribute(ApplicationDbContext)”的必需参数“db”对应的实参。
原代码示例
过滤器代码
[AttributeUsage(AttributeTargets.Class)] public class CustomPageFilterAttribute : Attribute, IAsyncPageFilter { protected ApplicationDbContext _db; public CustomPageFilterAttribute(ApplicationDbContext db) { _db = db; } public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { var something = _db.Customers.Find(1); return Task.CompletedTask; } public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { await next(); } }
Razor页面代码
[CustomPageFilterAttribute] public class ConfigUsuarioModel : PageModel { private readonly ApplicationDbContext _db; [BindProperty] public ConfigUsuario _configUsuario { get; set; } [TempData] public string StatusMessage { get; set; } public ConfigUsuarioModel(ApplicationDbContext db) { _db = db; } }
Program.cs注册DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString, sqlServerOptions => sqlServerOptions.CommandTimeout(90)));
正确实现方式
核心问题
特性是编译期实例化的,无法纳入ASP.NET Core的依赖注入生命周期管理,因此不能通过构造函数接收DI容器中的服务。下面提供两种可行方案:
方案1:拆分过滤器与特性标记
将过滤器逻辑和标记特性分离,由DI容器管理过滤器实例:
- 创建独立的过滤器类
public class CustomPageFilter : IAsyncPageFilter { private readonly ApplicationDbContext _db; public CustomPageFilter(ApplicationDbContext db) { _db = db; } public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { var something = _db.Customers.Find(1); return Task.CompletedTask; } public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { // 执行前逻辑 await next(); // 执行后逻辑 } }
- 创建标记用的空特性
[AttributeUsage(AttributeTargets.Class)] public class CustomPageFilterAttribute : Attribute { // 仅作为页面标记,无需逻辑 }
- 在Program.cs中注册并配置过滤器
builder.Services.AddScoped<CustomPageFilter>(); builder.Services.AddRazorPages(options => { // 配置过滤器仅对标记了CustomPageFilterAttribute的页面生效 options.Filters.Add(new FilterFactoryAttribute(typeof(CustomPageFilter)) { IsReusable = true }); });
- 在Razor页面添加标记
[CustomPageFilterAttribute] public class ConfigUsuarioModel : PageModel { // 原有代码保持不变 }
方案2:从请求上下文获取依赖
不拆分类,直接在过滤器方法中从HttpContext的服务容器获取依赖:
修改过滤器代码:
[AttributeUsage(AttributeTargets.Class)] public class CustomPageFilterAttribute : Attribute, IAsyncPageFilter { public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { // 从请求服务中获取DbContext实例 var db = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>(); var something = db.Customers.Find(1); return Task.CompletedTask; } public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { var db = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>(); // 执行前逻辑 await next(); // 执行后逻辑 } }
此时过滤器无需构造函数,Razor页面上的[CustomPageFilterAttribute]标记即可正常使用,不会再出现参数错误。
内容的提问来源于stack exchange,提问作者patsy2k
相关产品推荐
相关产品推荐

