日常生活的交流与学习

首页 新随笔 联系 管理

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的处理过程进行拦截和过滤。

  1. 接口定义和继承关系

    • IAsyncPageFilter接口继承自IFilterMetadata接口。IFilterMetadata是一个标记接口,用于表示某个类型是一个过滤器相关的元数据类型。
  2. 方法说明

    • OnPageHandlerExecutionAsync方法

      • 在模型绑定完成之后,在页面处理程序方法被调用之前执行。它接收两个参数:PageHandlerExecutingContext类型的contextPageHandlerExecutionDelegate类型的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类的详细分析:

  1. 类的定义和接口实现

    • DbContextTransactionPageFilter类实现了IAsyncPageFilter接口,这意味着它可以在异步的Razor页面处理过程中执行过滤逻辑。
  2. 方法分析

    • 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,以便下次可以重新开启新的事务。

  3. 配置方式

  • 通过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){}
}
  1. 类的定义和接口实现

    • ValidatorPageFilter类位于ContosoUniversity.Infrastructure命名空间下,实现了IPageFilter接口。IPageFilter接口定义了在页面处理过程中的三个关键阶段(处理程序方法选择、执行前、执行后)可以进行操作的方法。
  2. 方法分析

    • OnPageHandlerSelected方法
      • 该方法在页面处理程序方法被选择时调用,但在这里它没有执行任何实际的逻辑,为空方法。
    • OnPageHandlerExecuting方法
      • 这是该过滤器的核心方法,用于在页面处理程序执行前验证模型的有效性。
      • 首先检查context.ModelState.IsValid,如果模型状态无效:
        • 当请求方法是GET时,创建一个BadRequestResult实例,并将其设置为context.Result。这意味着如果是GET请求且模型验证失败,将返回一个400 Bad Request响应给客户端。
        • 当请求方法不是GET时,创建一个ContentResult实例。
        • context.ModelState序列化为JSON字符串,使用JsonConvert.SerializeObject方法,并设置ReferenceLoopHandling = ReferenceLoopHandling.Ignore来避免循环引用问题。
        • 将序列化后的JSON字符串设置为ContentResultContent属性,将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页面的请求处理过程中,都会经过这个过滤器来验证模型的有效性,确保只有在模型验证通过的情况下才会继续执行页面处理程序的核心逻辑,从而提高了应用程序的稳定性和数据的准确性。

posted on 2024-11-03 16:46  lazycookie  阅读(5)  评论(0编辑  收藏  举报