asp.net dotnet razor page mvc 过滤器 数据验证过滤器 数据库事务过滤器
Program.cs注册过滤器
services.AddRazorPages(opt =>
{
opt.Conventions.ConfigureFilter(new DbContextTransactionPageFilter());
opt.Conventions.ConfigureFilter(new ValidatorPageFilter());
});
在Program.cs中注册razorpage的过滤器
DbContextTransactionPageFilter
过滤器
-
这个过滤器主要用于处理数据库事务相关的操作。从
DbContextTransactionPageFilter
类的代码可以看到,它在OnPageHandlerExecutionAsync
方法中实现了事务的开始、提交和回滚逻辑 -
ValidatorPageFilter
过滤器
IAsyncPageFilter接口
#region Assembly Microsoft.AspNetCore.Mvc.RazorPages, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// D:\.nuget\packages\microsoft.aspnetcore.app.ref\6.0.30\ref\net6.0\Microsoft.AspNetCore.Mvc.RazorPages.dll
#endregion
#nullable enable
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Mvc.Filters
{
//
// Summary:
// 一个异步环绕页面处理方法执行的过滤器。这个过滤器仅在装饰在处理程序类型上时执行,而不在单个处理程序方法上执行。
public interface IAsyncPageFilter : IFilterMetadata
{
// Summary:
// 在模型绑定完成之后,在处理程序方法被调用之前异步调用。
// Parameters:
// context:
// 是Microsoft.AspNetCore.Mvc.Filters.PageHandlerExecutingContext类型。
// next:
// 是Microsoft.AspNetCore.Mvc.Filters.PageHandlerExecutionDelegate类型。被调用来执行下一个页面过滤器或处理程序方法本身。
// Returns:
// 一个System.Threading.Tasks.Task,完成时表示过滤器已执行。
Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next);
// Summary:
// 在处理程序方法被选择之后,但在模型绑定发生之前异步调用。
// Parameters:
// context:
// 是Microsoft.AspNetCore.Mvc.Filters.PageHandlerSelectedContext类型。
// Returns:
// 一个System.Threading.Tasks.Task,完成时表示过滤器已执行。
Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context);
}
}
这段C# 代码定义了一个名为IAsyncPageFilter
的接口,它位于Microsoft.AspNetCore.Mvc.Filters
命名空间中。该接口用于在ASP.NET Core的MVC框架中对Razor Pages的处理过程进行拦截和过滤。
-
接口定义和继承关系
IAsyncPageFilter
接口继承自IFilterMetadata
接口。IFilterMetadata
是一个标记接口,用于表示某个类型是一个过滤器相关的元数据类型。
-
方法说明
-
OnPageHandlerExecutionAsync
方法- 在模型绑定完成之后,在页面处理程序方法被调用之前执行。它接收两个参数:
PageHandlerExecutingContext
类型的context
和PageHandlerExecutionDelegate
类型的next
。其中context
包含了当前页面处理执行的上下文信息,next
是一个委托,用于执行下一个页面过滤器或者直接执行页面处理程序方法本身。该方法返回一个Task
,当这个Task
完成时,表示这个过滤器的执行逻辑已经完成。
- 在模型绑定完成之后,在页面处理程序方法被调用之前执行。它接收两个参数:
-
OnPageHandlerSelectionAsync
方法- 在页面处理程序方法被选择之后,但在模型绑定发生之前执行。它接收一个
PageHandlerSelectedContext
类型的context
参数,该参数包含了页面处理程序被选择的相关上下文信息。该方法同样返回一个Task
,当Task
完成时,表示过滤器在这个阶段的执行已经完成。
- 在页面处理程序方法被选择之后,但在模型绑定发生之前执行。它接收一个
-
总的来说,这个接口定义了在Razor Pages处理过程中的两个关键阶段(处理程序方法选择之后和执行之前)可以进行异步操作的规范,使得开发人员可以在这些阶段插入自定义的逻辑,比如进行权限验证、日志记录、修改模型状态等操作。
DbContextTransactionPageFilter
过滤器
public class DbContextTransactionPageFilter : IAsyncPageFilter
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) => Task.CompletedTask;
public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
{
var dbContext = context.HttpContext.RequestServices.GetRequiredService<SchoolContext>();
try
{
await dbContext.BeginTransactionAsync();
var actionExecuted = await next();
if (actionExecuted.Exception != null && !actionExecuted.ExceptionHandled)
{
dbContext.RollbackTransaction();
}
else
{
await dbContext.CommitTransactionAsync();
}
}
catch (Exception)
{
dbContext.RollbackTransaction();
throw;
}
}
}
以下是对DbContextTransactionPageFilter
类的详细分析:
-
类的定义和接口实现
DbContextTransactionPageFilter
类实现了IAsyncPageFilter
接口,这意味着它可以在异步的Razor页面处理过程中执行过滤逻辑。
-
方法分析
-
OnPageHandlerSelectionAsync
方法 -
代码实现为
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) => Task.CompletedTask;
-
这个方法在页面处理程序被选择时调用,但在这里它没有执行任何实际的逻辑,只是直接返回一个已完成的任务,表示不需要在这个阶段进行任何处理。
-
OnPageHandlerExecutionAsync
方法-
这是该过滤器的核心方法,用于处理页面请求的执行过程中的事务逻辑。
-
首先获取
SchoolContext
实例: -
通过
var dbContext = context.HttpContext.RequestServices.GetRequiredService<SchoolContext>();
从当前的HttpContext
的服务提供者中获取SchoolContext
实例,这个实例将用于数据库操作和事务管理。 -
然后开始事务:
-
调用
await dbContext.BeginTransactionAsync();
开始一个数据库事务。如果当前已经存在一个未完成的事务(通过_currentTransaction
字段判断),则直接返回,不会重复开启事务。 -
接着执行页面处理程序并处理结果:
-
通过
var actionExecuted = await next();
执行下一个过滤器或页面处理程序,并获取执行结果。 -
如果执行过程中发生异常并且没有被处理(即
actionExecuted.Exception!= null &&!actionExecuted.ExceptionHandled
),则调用dbContext.RollbackTransaction();
回滚事务。 -
如果没有发生异常或者异常已经被处理,则调用
await dbContext.CommitTransactionAsync();
提交事务。 -
最后处理事务对象:
-
在提交或回滚事务之后,无论事务是否成功完成,都会在
finally
块中检查_currentTransaction
是否为null
。如果不为null
,则调用_currentTransaction.Dispose();
释放事务资源,并将_currentTransaction
设置为null
,以便下次可以重新开启新的事务。
-
-
-
配置方式:
- 通过
opt.Conventions.ConfigureFilter(new DbContextTransactionPageFilter());
将DbContextTransactionPageFilter
过滤器添加到Razor Pages的过滤器集合中。这样,在每个Razor页面的请求处理过程中,都会经过这个过滤器来处理数据库事务。
ValidatorPageFilter
过滤器
public class ValidatorPageFilter : IPageFilter
{
public void OnPageHandlerSelected(PageHandlerSelectedContext context){}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
if (!context.ModelState.IsValid)
{
if (context.HttpContext.Request.Method == "GET")
{
var result = new BadRequestResult();
context.Result = result;
}
else
{
var result = new ContentResult();
var content = JsonConvert.SerializeObject(context.ModelState,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
result.Content = content;
result.ContentType = "application/json";
context.HttpContext.Response.StatusCode = 400;
context.Result = result;
}
}
}
public void OnPageHandlerExecuted(PageHandlerExecutedContext context){}
}
-
类的定义和接口实现
ValidatorPageFilter
类位于ContosoUniversity.Infrastructure
命名空间下,实现了IPageFilter
接口。IPageFilter
接口定义了在页面处理过程中的三个关键阶段(处理程序方法选择、执行前、执行后)可以进行操作的方法。
-
方法分析
OnPageHandlerSelected
方法- 该方法在页面处理程序方法被选择时调用,但在这里它没有执行任何实际的逻辑,为空方法。
OnPageHandlerExecuting
方法- 这是该过滤器的核心方法,用于在页面处理程序执行前验证模型的有效性。
- 首先检查
context.ModelState.IsValid
,如果模型状态无效:- 当请求方法是
GET
时,创建一个BadRequestResult
实例,并将其设置为context.Result
。这意味着如果是GET
请求且模型验证失败,将返回一个400 Bad Request
响应给客户端。 - 当请求方法不是
GET
时,创建一个ContentResult
实例。 - 将
context.ModelState
序列化为JSON字符串,使用JsonConvert.SerializeObject
方法,并设置ReferenceLoopHandling = ReferenceLoopHandling.Ignore
来避免循环引用问题。 - 将序列化后的JSON字符串设置为
ContentResult
的Content
属性,将ContentType
属性设置为application/json
,并将HttpContext.Response.StatusCode
设置为400
,最后将ContentResult
设置为context.Result
。这意味着对于非GET
请求且模型验证失败,将返回一个包含模型验证错误信息的400 Bad Request
响应,格式为JSON。
- 当请求方法是
OnPageHandlerExecuted
方法- 该方法在页面处理程序执行后调用,但在这里它没有执行任何实际的逻辑,为空方法。
在整个项目中,这个过滤器通过services.AddRazorPages(opt => { opt.Conventions.ConfigureFilter(new ValidatorPageFilter()); });
被注册到Razor Pages的过滤器集合中。这样,在每个Razor页面的请求处理过程中,都会经过这个过滤器来验证模型的有效性,确保只有在模型验证通过的情况下才会继续执行页面处理程序的核心逻辑,从而提高了应用程序的稳定性和数据的准确性。