ASP.NET Core 中的五种过滤器


前言

👨‍💻👨‍🌾📝记录学习成果,以便温故而知新

本文以命名空间Microsoft.AspNetCore.Mvc.Filters下的过滤器学习的过程做一个记录。广大网友们都说是过滤器,Java里貌似也说是过滤器,所以就顺着大家叫了。但是官网上却是叫“筛选器”。

Microsoft.AspNetCore.Mvc.Filters 命名空间官网:https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.filters?view=aspnetcore-7.0

讲实话,微软的官网现在感觉有点凌乱,有些看似官网的却是志愿者还是啥的写的内容。所以如果有什么差错还请谅解。


一、过滤器介绍

1.五种过滤器

广大网友们所说的五种过滤器,当然它们都有对应的异步过滤器。由于学习是循序渐进的,先学习同步的,等掌握好了以后再去学习异步的。

(1)IActionFilter

环绕操作执行的筛选器。

两个方法:

1.OnActionExecuted(ActionExecutedContext)

在操作执行后、操作结果之前调用。

2.OnActionExecuting(ActionExecutingContext)

在操作执行之前调用,在模型绑定完成后调用。

(2)IAuthorizationFilter

确认请求授权的筛选器。

一个方法:

OnAuthorization(AuthorizationFilterContext)

在筛选器管道的早期调用,以确认请求是否已获得授权。

(3)IExceptionFilter

在操作引发 Exception后运行的筛选器。

一个方法:

OnException(ExceptionContext)

在操作引发 Exception后调用 。

(4)IResourceFilter

包含模型绑定执行的筛选器、操作 (和筛选器) 以及操作结果 (和筛选器) 。

两个方法:

1.OnResourceExecuted(ResourceExecutedContext)

执行资源筛选器。 在执行管道的其余部分后调用。

2.OnResourceExecuting(ResourceExecutingContext)

执行资源筛选器。 在执行管道的其余部分之前调用。

(5)IResultFilter

包含操作执行结果的筛选器已成功从操作返回。

IResultFilter 如果授权筛选器或资源筛选器使请求短路以阻止操作的执行,则不会执行 和 IAsyncResultFilter 实例。 IResultFilter. IResultFilter 在异常筛选器通过生成操作结果处理异常的情况下,也不会执行 和 IAsyncResultFilter 实现。

两个方法:

1.OnResultExecuted(ResultExecutedContext)

在操作结果执行之后调用。

2.OnResultExecuting(ResultExecutingContext)

在操作结果执行之前调用。

2.另外两种过滤器

官网中还有另外两种过滤器,不知道广大网友为什么不介绍,只能揣测是不常用。简单介绍如下:

(1)IOrderedFilter

一个筛选器,指定它应运行的相对顺序。

(2)IPageFilter

一个筛选器,用于包围页面处理程序方法的执行。 仅当对处理程序的类型进行修饰时,才会执行此筛选器,而不是在单个处理程序方法上执行。

3.三个特性

很奇怪的是看到很多网友介绍的文章在定义过滤器特性时都没有继承现成的特性,而是实现的接口。

(1)ActionFilterAttribute

异步包围操作的执行和操作结果的抽象筛选器。 子类应替代 、 OnActionExecuted(ActionExecutedContext) 或 OnActionExecutionAsync(ActionExecutingContext, ActionExecutionDelegate) (但不替代OnActionExecutionAsync(ActionExecutingContext, ActionExecutionDelegate)OnActionExecuting(ActionExecutingContext))以及其他两个之一。 同样,子类应替代 、 OnResultExecuted(ResultExecutedContext) 或 OnResultExecutionAsync(ResultExecutingContext, ResultExecutionDelegate) (但不能OnResultExecutionAsync(ResultExecutingContext, ResultExecutionDelegate))OnResultExecuting(ResultExecutingContext)以及其他两个之一。

(2)ExceptionFilterAttribute

在操作引发 Exception后异步运行的抽象筛选器。 子类必须替代 或,OnExceptionAsync(ExceptionContext)但不能同时重写OnException(ExceptionContext)两者。

我再次确认了上面这段的引用,官网是:
在这里插入图片描述
只能无语(我竟无言以对)!!!

(3)ResultFilterAttribute

异步包围操作结果执行的抽象筛选器。 子类必须替代 、 OnResultExecuted(ResultExecutedContext) 或 OnResultExecutionAsync(ResultExecutingContext, ResultExecutionDelegate) (但不能OnResultExecutionAsync(ResultExecutingContext, ResultExecutionDelegate)替代OnResultExecuting(ResultExecutingContext))和另外两个之一。

以上内容看似洋洋洒洒,实际上主要来源于官网。对于这些知识的定义,也只能相信官网,不可能自己发挥的。下面是代码演示,就有了发挥的空间。

二、过滤器演示代码

本文的演示环境是Win10,目标框架是.NET Core 2.1,建的是ASP.NET Core Web 应用程序。不同的环境可能会有差别。

1.实现接口

(1)ActionFilter1Attribute.cs

namespace TestFilter.Filter
{
    public class ActionFilter1Attribute : Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Debug.WriteLine("ActionFilter1Attribute OnActionExecuted");
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            Debug.WriteLine("ActionFilter1Attribute OnActionExecuting");
        }
    }
}

(2)ActionFilter2Attribute.cs

namespace TestFilter.Filter
{
    public class ActionFilter2Attribute : Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Debug.WriteLine("ActionFilter2Attribute OnActionExecuted");
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            Debug.WriteLine("ActionFilter2Attribute OnActionExecuting");
        }
    }
}

定义了两个过滤器是想看同时注册时的调用顺序,如下测试代码:

// GET: api/User/ShowAction1
[HttpGet("ShowAction1")]
[ActionFilter1, ActionFilter2]
public IActionResult ShowAction1()
{
    ContentResult cr = new ContentResult();
    cr.Content = "ShowAction1";
    return cr;
}

控制台输出:
在这里插入图片描述
交换一下过滤器的顺序的代码:

// GET: api/User/ShowAction2
[HttpGet("ShowAction2")]
[ActionFilter2, ActionFilter1]
public IActionResult ShowAction2()
{
    ContentResult cr = new ContentResult();
    cr.Content = "ShowAction2";
    return cr;
}

控制台输出:
在这里插入图片描述
两张截图对比一下,结果很清晰的,所以也用不着总结了。

这里是把特性加在方法上,是给单个方法注册过滤器,下面类似情况不再重复说明。

(3)AuthorizationFilterAttribute.cs

确认授权过滤器特性定义了一个属性,是像简单演示一下权限是如何传参的。记得Java的shiro框架中logical来说明权限数组是“与”逻辑还是“或”逻辑,这里就不细说了,只要明白套路就行。所谓“运用之妙,存乎一心”。

namespace TestFilter.Filter
{
    public class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter
    {
        /// <summary>
        /// 权限
        /// </summary>
        private string[] Privilege { get; set; }

        public AuthorizationFilterAttribute(params string[] privilege)
        {
            Privilege = privilege;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            Debug.WriteLine("权限数量:" + Privilege.Length);
            Debug.WriteLine("AuthorizationFilter OnAuthorization");
        }
    }
}

测试代码如下:

// GET: api/User/ShowAuthorization1
[HttpGet("ShowAuthorization1")]
[AuthorizationFilter]
public IActionResult ShowAuthorization1()
{
    ContentResult cr = new ContentResult();
    cr.Content = "Authorization1";
    return cr;
}

控制台输出如图:
在这里插入图片描述
又一段测试代码:

// GET: api/User/ShowAuthorization2
[HttpGet("ShowAuthorization2")]
 [AuthorizationFilter("Admin", "User")]
 public IActionResult ShowAuthorization2()
 {
     ContentResult cr = new ContentResult();
     cr.Content = "Authorization2";
     return cr;
 }

控制台输出:
在这里插入图片描述
这里用可变长参数给特性传参,模拟传"Admin"与"User"两类权限。

(4)ExecptionFilter.cs

由于异常处理通常是全局的,所以就没有定义成特性。

namespace TestFilter.Filter
{
    public class ExecptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            Debug.WriteLine(context.Exception);

            context.Result = new ObjectResult("ExceptionHandled ");
            context.ExceptionHandled = true;
        }
    }
}

在Startup.cs文件中ConfigureServices方法里注册全局过滤器

services.AddMvc(option => {
    option.Filters.Add<ExecptionFilter>();//全局异常
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

测试代码如下:

// GET: api/User/ShowException
[HttpGet("ShowException")]
public IActionResult ShowException()
{
    throw new Exception("ShowException");
}

控制台输出如图:
在这里插入图片描述
在集成开发环境中要点一下“继续”才能看到控制台的输出,否则流程会被阻塞。

(5)ResourceFilterAttribute.cs

namespace TestFilter.Filter
{
    public class ResourceFilterAttribute : Attribute, IResourceFilter

    {
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            Debug.WriteLine("ResourceFilterAttribute OnResourceExecuted");
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            Debug.WriteLine("ResourceFilterAttribute OnResourceExecuting");
        }
    }
}

测试代码如下:

// GET: api/User/ShowResource
[HttpGet("ShowResource")]
[ResourceFilter]
public IActionResult ShowResource()
{
    ContentResult cr = new ContentResult();
    cr.Content = "ShowResource";
    return cr;
}

控制台输出如图:
在这里插入图片描述

(6)ResultFilter1Attribute.cs

namespace TestFilter.Filter
{
    public class ResultFilter1Attribute : Attribute, IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext context)
        {
            Debug.WriteLine("ResultFilterAttribute OnResultExecuted");
        }

        public void OnResultExecuting(ResultExecutingContext context)
        {
            Debug.WriteLine("ResultFilterAttribute OnResultExecuting");
        }
    }
}

测试代码如下:

// GET: api/User/ShowResult1
[HttpGet("ShowResult1")]
[ResultFilter1]
public IActionResult ShowResult1()
{
    ContentResult cr = new ContentResult();
    cr.Content = "ShowResult1";
    return cr;
}

在这里插入图片描述

(7)综合测试

测试代码:

// GET: api/User/Comprehensive
[HttpGet("Comprehensive")]
[ActionFilter1]
[AuthorizationFilter]
[ResourceFilter]
[ResultFilter1]
public IActionResult Comprehensive()
{
    ContentResult cr = new ContentResult();
    cr.Content = "Comprehensive";
    return cr;
}

控制台输出如图:
在这里插入图片描述
这张截图很能说明各种过滤器的执行顺序。
异常过滤器会阻断一些过滤器的执行,有兴趣的自己可以去测试一下。

2.继承类

(1)LogActionFilter.cs

这段代码来源于文章了解操作筛选器 (C#)“创建日志操作筛选器”一节,感觉很有趣,就借用了。

namespace TestFilter.Filter
{
    public class LogActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            Log("OnActionExecuting", filterContext.RouteData);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            Log("OnActionExecuted", filterContext.RouteData);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            Log("OnResultExecuting", filterContext.RouteData);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            Log("OnResultExecuted", filterContext.RouteData);
        }


        private void Log(string methodName, RouteData routeData)
        {
            var controllerName = routeData.Values["controller"];
            var actionName = routeData.Values["action"];
            var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
            Debug.WriteLine(message, "Action Filter Log");
        }
    }
}

测试代码:

namespace TestFilter.Controllers.Api
{
    [Route("api/[controller]")]
    [ApiController]
    [LogActionFilter]
    public class RoleController : ControllerBase
    {
        // GET: api/Role/Show
        [HttpGet("Show")]
        public IActionResult Show()
        {
            ContentResult cr = new ContentResult();
            cr.Content = "Show";
            return cr;
        }
    }
}

控制台输出如图:
在这里插入图片描述
这里的代码一是想介绍一下在类上注册过滤器;二是简单介绍获取方法的信息,其实还可以获取方法的传参与返回,限于篇幅就不展开了;三是想展示一下ActionFilterAttribute类可以覆盖的内容。

(2)ResultFilter.cs

namespace TestFilter.Filter
{
    public class ResultFilter : ResultFilterAttribute
    {
        public override void OnResultExecuted(ResultExecutedContext context)
        {
            Debug.WriteLine("ResultFilter OnResultExecuted");
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            Debug.WriteLine("ResultFilter OnResultExecuting");
        }
    }
}

测试代码:

// GET: api/User/ShowResult2
[HttpGet("ShowResult2")]
[ResultFilter]
public IActionResult ShowResult2()
{
    ContentResult cr = new ContentResult();
    cr.Content = "ShowResult2";
    return cr;
}

控制台输出如图:
在这里插入图片描述
这里也是两个方法,没有发现明显区别。

因为考虑到异常一般是全局处理,所以没有研究ExceptionFilterAttribute,感觉如果项目定义自己的异常体系倒是有必要针对不同异常来做处理。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ASP.NET Core 3.1是一个跨平台、高性能的开源框架,它可以帮助我们快速地构建Web应用程序。ASP.NET Core 3.1文教程可以为初学者提供一个快速上手的指南,帮助他们了解和掌握该框架的各种功能。 在学习ASP.NET Core 3.1教程之前,我们需要了解一些基本的编程概念和技能, 包括C#语言的基础知识、MVC(Model View Controller)等常见的编程模式、以及前端技术如HTML、CSS和JavaScript等。此外,我们还需要对.NET Core框架有一定的了解,如.NET Core的概念、架构和基础组件等。 学习ASP.NET Core 3.1的教程需要深入理解其设计方案和特点,例如跨平台、高性能、依赖注入、实时通信等。此外,我们还需要熟悉其主要组件,如ASP.NET Core间件、MVC框架、Entity Framework Core等。 在学习ASP.NET Core 3.1的教程时,我们需要通过实践才能更好地理解其所涉及的技术和概念。因此,我们需要通过编写各种实际的Web应用程序和示例,来实践和掌握所学的技巧和知识。 总之,学习ASP.NET Core 3.1的文教程需要较深的前置知识储备和实操经验,而且需要坚持不懈地学习和练习以提高自己的技能水平。 ### 回答2: ASP.NET Core 3.1是目前为止最新的ASP.NET Core版本,它是一个跨平台的Web应用程序开发框架。对于想要学习ASP.NET Core 3.1的开发者来说,文教程是非常重要的。 现在,有很多文教程可以帮助开发者快速入门ASP.NET Core 3.1。这些教程通常包括以下内容: 1. ASP.NET Core 3.1的基础知识:网页处理、路由、控制器等; 2. ASP.NET Core 3.1的模型、视图和控制器; 3. 动作过滤器和特性; 4. 实体框架和数据库相关操作; 5. API设计和测试等。 这些教程通常包含实例和练习,能够帮助开发者深入理解ASP.NET Core 3.1的开发原理。另外,一些知名的在线教育平台,如网易云课堂等,也提供了ASP.NET Core 3.1的文课程,有兴趣的开发者可以去尝试。 总的来说,学习ASP.NET Core 3.1需要投入时间和精力,但是文教程能够让初学者更加轻松地掌握ASP.NET Core 3.1的开发技能,更好地进行ASP.NET Core 3.1的开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值