谈谈Asp.Net Core Filter

前言

最近一直忙于做移动端前端页面的编写,应该快有三周左右没再去编写后端的相关业务逻辑,尤其是ASP.NET CORE的相关内容,感觉学习的方向发生了偏移。这种感觉源于对时间的紧迫感,因为无论前端还是后端,研究起来都是无底洞,没有几个人敢说自己精通某个领域的知识。害怕的是在前端这块玩一玩,又搞搞后端,时间就这这样浪费掉了。但是目前所学的还好,也算一种锻炼,也确实提高了编写前端页面的能力,确切的说是CSS以及对Boostrap的了解。暂且这样吧,一步步来。

下面回归正题。

文章整理转载自:donet 博士,草根专栏

什么是AOP?

先看百度的定义:“全称Aspect Oriented Programming,面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。”

AOP技术利用一种称为“横切”的技术,剖解开封装对象的内部,将影响多个类的公共行为封装到一个可重用的模块中,并将其命名为Aspect切面。所谓的切面,简单来说就是与业务无关,却为业务模块所共同调用的逻辑,将其封装起来便于减少系统的重复代码,降低模块的耦合度,有利用未来的可操作性和可维护性。

利用AOP可以对业务逻辑各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

注:Filter 是专用于 MVC 管道的,不同于之前讲的 ASP.NET Core 的管道。

AOP的使用场景主要包括日志记录、性能统计、安全控制、事务处理、异常处理

Filter-过滤器

Filter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。通过不同的Filter可以有效处理封包进出的加工,本篇将介绍ASP.NET Core的五种Filter运作方式。

ASP.NET Core 有以下五种Filter 可以使用:

  • Authorization Filter:Authorization是五种Filter中优先级最高的,通常用于验证Request合不合法,不合法后面就直接跳过。

  • Resource Filter:Resource是第二优先,会在Authorization之后,Model Binding之前执行。通常会是需要对Model加工处理才用。

  • Exception Filter:异常处理的Filter。

  • Action Filter:最常使用的Filter,封包进出都会经过它,使用上没什么需要特别注意的。跟Resource Filter很类似,但并不会经过Model Binding。

  • Result Filter:当Action完成后,最终会经过的Filter。

MVC 管道:

image.png

Authonization Filter

权限控制过滤器 通过 Authonization Filter 可以实现复杂的权限角色认证登陆授权等操作 实现事例代码如下:

 public class AuthonizationFilter :Attribute,IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            //这里可以做复杂的权限控制操作
            if (context.HttpContext.User.Identity.Name != "1") //简单的做一个示范
            {
                //未通过验证则跳转到无权限提示页
                RedirectToActionResult content = new RedirectToActionResult("NoAuth", "Exception", null);
                context.Result = content;
            }
        }
    }

Resource Filter

资源过滤器 可以通过Resource Filter 进行资源缓存防盗链等操作。使用Resource Filter 要求实现IResourceFilter 抽象接口

public class ResourceFilter : Attribute,IResourceFilter
    {
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            // 执行完后的操作
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            // 执行中的过滤器管道
        }
    }

Exception Filter

通过Execption Filter 过滤器可以进行全局的异常日志收集 等操作。

使用Execption Filter 要求实现IExceptionFilter 抽象接口IExceptionFilter接口会要求实现OnException方法,当系统发生未捕获异常时就会触发这个方法。OnException方法有一个ExceptionContext异常上下文,其中包含了具体的异常信息,HttpContext及mvc路由信息。系统一旦出现未捕获异常后,比较常见的做法就是使用日志工具,将异常的详细信息记录下来,方便修正调试。下面是日志记录的实现。

 public class ExecptionFilter : Attribute, IExceptionFilter
  {
        private ILogger<ExecptionFilter> _logger;
        //构造注入日志组件
        public ExecptionFilter(ILogger<ExecptionFilter> logger)
        {
            _logger = logger;
        }

        public void OnException(ExceptionContext context)
        {
            //日志收集
            _logger.LogError(context.Exception, context?.Exception?.Message??"异常");
        }
    }

Action Filter

作用:可以通过ActionFilter 拦截 每个执行的方法进行一系列的操作,比如:执行操作日志参数验证权限控制 等一系列操作。使用Action Filter 需要实现IActionFilter 抽象接口,IActionFilter 接口要求实现OnActionExecuted 和OnActionExecuting 方法。

 public class ActionFilter : Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            //执行完成....
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            //执行中...
        }
    }

Result Filter

结果过滤器,可以对结果进行格式化、大小写转换等一系列操作。

使用Result Filter 需要实现IResultFilter 抽象接口,接口要求实现OnResultExecuting 方法 和OnResultExecuted 方法

  • OnResultExecuting :Called before the action result executes. 在操作结果执行之前调用

  • OnResultExecuted  :Called after the action result executes. 在操作结果执行之后调用

具体代码实现代码如下:

public class ResultFilter : Attribute, IResultFilter
 {
        public void OnResultExecuted(ResultExecutedContext context)
        {
            // 在结果执行之后调用的操作...
        }

        public void OnResultExecuting(ResultExecutingContext context)
        {
            // 在结果执行之前调用的一系列操作
        }
    }

 

Asp.Net Core 过滤器的注册方式

这一篇章主要来分析探讨Asp.Net Core 中过滤器的三种注册方式ActionController全局 。

Action 注册方式

Action 注册方式是局部注册方式,针对控制器中的某个方法上标注特性的方式进行注册,代码如下:

[AuthonizationFilter()]
 public IActionResult Index()
 {
            return View();
 }

Controller 注册方式

了解过Action 特性注册方式的同学,一定发现了它的不好之处就是我一个控制器里面需要使用同一套Filter 的时候,需要一个一个Action 标注特性注册,是不是很繁琐呢?有没有其他方式进行代替这些繁琐的操作呢?微软给我们提供了简便的控制器标注注册方式,代码如下。

[AuthonizationFilter()]
 public class FirstController : Controller
  {
        private ILogger<FirstController> _logger;

        public FirstController(ILogger<FirstController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index()
        {
            return View();
        }
 }

全局注册方式

现在有些同学考虑了一些全局的情况,比如我要全局处理系统中的异常,或者收集操作日志等,需要全局注册一个ExceptionFilter 来实现,就不需要每一个Controller 中进行代码注册,方便快捷。代码如下:

services.AddMvc(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());

    //options.Filters.Add(new LogResourceFilter());
    //options.Filters.Add(typeof(LogAsyncResourceFilter));
    options.Filters.Add<LogResourceFilter>();
});

 TypeFilter 和 ServiceFilter 注册方式

上面的五大过滤器中事例代码中其中有一个过滤器的代码比较特,再来回顾ExceptionFilter过滤器的实现代码:

public class ExecptionFilter : Attribute, IExceptionFilter
    {
        private ILogger<ExecptionFilter> _logger;
        //构造注入日志组件
        public ExecptionFilter(ILogger<ExecptionFilter> logger)
        {
            _logger = logger;
        }

        public void OnException(ExceptionContext context)
        {
            //日志收集
            _logger.LogError(context.Exception, context?.Exception?.Message??"异常");
        }
    }

从上面的代码中可以发现 ExceptionFilter 过滤器实现中存在日志服务的构造函数的注入,也就是说该过滤器依赖于其他的日志服务,但是日志服务都是通过DI 注入进来的;再来回顾下上面Action 注册方式或者Controller 注册方式 也即Attribute 特性标注注册方式,本身基础的特性是不支持构造函数的,是在运行时注册进来的,那要解决这种本身需要对服务依赖的过滤器需要使用 TypeFilter 或者ServiceFilter 方式进行过滤器的标注注册。

TypeFilter 和ServiceFilter 的区别。

  • ServiceFilter和TypeFilter都实现了IFilterFactory

  • ServiceFilter需要对自定义的Filter进行注册,TypeFilter不需要

  • ServiceFilter的Filter生命周期源自于您如何注册,而TypeFilter每次都会创建一个新的实例

TypeFilter 使用方式

[TypeFilter(typeof(ExecptionFilter))]
public IActionFilter Index2()
{
      return View();
}

 

通过上面的代码可以发现AuthonizationFilter 是默认的构造器,但是如果过滤器中构造函数中存在参数,需要注入服务那该怎么办呢?,比如上面的ExceptionFilter 代码,就不能使用这种方式进行注册,需要使用服务特性的方式,我们可以选择使用 代码如下:

控制器中的代码如下:

[ServiceFilter(typeof(ExecptionFilter))]
public IActionFilter Index2()
{
           return View();
}

注册服务的代码如下:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
       Console.WriteLine("ConfigureServices");
       services.AddControllersWithViews();

       //services.AddControllersWithViews(option=> {
       //    option.Filters.Add<ExecptionFilter>();
       //});
        
        //注册过滤器服务,使用ServiceFilter 方式必须要注册 否则会报没有注册该服务的相关异常
        services.AddSingleton<ExecptionFilter>();
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值