D-15 过滤器 ? filter ? attribute

filter

眼尖的小光在昨日的内容中看到了一个有趣的东西,就是MiddlewareFilter,所以这个filter又困扰了他一整晚,所以一大早他就来了解甚麽是filter。

本文同步放置於此

过滤器是甚麽

「前辈阿,昨天遇到的一个MiddlewareFilter这是甚麽东西啊?」
一大早小光就来问大头关於过滤器的东西,因为这问题困扰了他一整晚所以他的黑眼圈都跑出来了。
「哈哈哈,你的眼睛真利阿,没想到这样的东西都会被你注意到,那我们今天就来说明一下甚麽是过滤器。」
刚说完这句话的大头似乎想到甚麽停顿了一下,不过过了几秒後他就这麽说了。
「不过在说明过滤器之前有个东西要先介绍,那就是属性。」

属性 attribute

在说明过滤器之前要先说明属性,所以请大家先看一下这个属性,这边的属性是attribute跟前面讲的property中文翻译是一样,但是内容差很多,所以本篇所说的属性都是指attribute,这边提到的属性功用很多,但是一样的地方都是以[]包覆起来的。然而在本篇用到的属性的功用是挂上该过滤器的属性就可以在执行该Action或是该Controller的Action都会进入过滤器之中,就视该过滤器是挂在Controller还是哪个Action,所以接下来开始说明过滤器。

过滤器 filter

提到过滤器还是会提到请求的流水线,但目前要说的是通过中介层後面那一段,所以大家先看一下过滤器

甚麽是过滤器

所谓的过滤器就是在请求的流水线进入Action之前跟之後会做些处理的动作,所以大家先看一下下图。

过滤器的流水线 过滤器的流水线

所以说当路由中到特定的Action之後要准备执行之前会先检查该Action有没有挂过滤器的的属性,当有挂特定过滤器的属性时会先执行该过滤器,并且在结束时会执行该过滤器。

过滤器种类

虽然说都是过滤器,但是过滤器也有许多种类,请参考下列表格。

种类 内容
授权 优先执行,用来判断使用者是否已针对要求取得授权。 如果要求未获授权,会进行较短的线路。
资源 会在授权之後执行。在模型系结之前执行程序码。并在管线的其余部分完成之後执行程序码。
动作 在呼叫动作方法之前和之後立即执行程序码,可以变更传递至动作的引数。并且可以变更动作传回的结果。不支援Razor页面。
例外状况 会将全域原则套用至回应主体写入之前发生的未处理例外状况。
结果 会在执行动作结果之前和之後立即执行程序码。 它们只有在动作方法执行成功时才执行。 它们适用於必须包围检视或格式器执行的逻辑。

而过滤器他们之间执行的先後顺序如下图所示。

过滤器类别间的流水线 过滤器类别间的流水线

实做过滤器

我们这边以动作过滤器为例子来说明如何实作一个过滤器,所以请大家先看下列内容

public class CustomActionFilter : IActionFilter 
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // 执行动作前的处理
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // 执行动作後的处理
    }
}

所以过滤器的实作就是这麽简单,想好你需要做些甚麽在对的时间点实作即可,不过这边有分两种介面,除了上述的IActionFilter之外,还有IAsyncActionFilter,这边有个注意事项,请实作同步非同步版本的筛选条件介面,而不要同时实作这两者。执行阶段会先检查以查看筛选条件是否会实作非同步介面,如果是,便会呼叫该介面。 如果没有,它会呼叫同步介面的方法。如果同时在单一类别中实作非同步和同步介面,系统只会呼叫非同步方法。接下来在看看要如何把这过滤器挂上去。

使用过滤器

依据过滤器的范围有分为以下两种,

  • 全域
  • 区域

关於全域的过滤器可以用以下方式使用。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add(typeof(CustomActionFilter),
                            int.MinValue);
    });
}

而区域的过滤器有三个挂上过滤器的方法,如下列所示。

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • IFilterFactory。

首先说明如何使用ServiceFilterTypeFilter方式挂上过滤器。

// 用ServiceFilter在Action挂上过滤器
[ServiceFilter(typeof(CustomActionFilter))]
public IActionResult Index()
{
    return View();
}

// 用TypeFilter在Action挂上过滤器
[TypeFilter(typeof(CustomActionFilter),
    Arguments = new object[] { "这是参数" })]
public IActionResult Hi(string name)
{
    return Content($"Hi {name}");
}

以上两个使用的方式差别如下,使用TypeFilter参考的类型不需要向DI容器注册。不过它们的相依性会由DI容器满足。而且TypeFilter可以选择性地接受类型的建构函式引数。而ServiceFilter需要先在DI注册过滤器。

最後用IFilterFactory挂上过滤器的方式如下。

// 工厂的实作
public class CustomActionFactoryAttribute : Attribute, IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new CustomActionFilter();
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

// 挂工厂在方法上
[CustomActionFactoryAttribute]
public IActionResult CustomActionFactory()
{
    // ...
}

这边要注意IFilterFactory.IsReusable当过滤器的来源是明确的、为无状态,而且可以在多个HTTP要求中安全地使用时,才设定为传回true

後记

「前辈阿,这几天讲的很多东西都在路由、中介层跟过滤器做完了,那Action要做甚麽阿。」
听完了这几天的内容後小光这麽问大头。
「哈哈哈,你太小看网页程序了,你这问题明天就会告诉你Controller跟Action要做甚麽动作,其中一项就是画面渲染。」
所以大家就期待一下明天的razor渲染了。


<<:  Day 15 再手动安装个 Python3 容器看看

>>:  负责任的机器学习专案

IOS、Python自学心得30天 Day-29 连接Firebase辨识

前言: 衔接完成 程序码: // // ViewController.swift // Dog Br...

[day24]Vue实作-交易建立页面_完成版

调整 目前虽然可以送交易,但还没有解析回覆的结果,趁连假第一天来处理一下!! 解析订单送出後回覆之资...

[第十四只羊] 迷雾森林舞会VII 开完房间後走进房间

天亮了 昨晚是平安夜 关於迷雾森林故事 焦虑抑制剂 4号:我跟全场站不同边耶,我站7耶,我跟7号玩家...

Day2 - Canvas基础概论 I - 成为Canvas Ninja ~ 理解2D渲染的精髓

Let's Start From Scratch 本系列文章的头几篇我决定还是带点基础的东西,但是我...

Day38 参加职训(机器学习与资料分析工程师培训班),RNN

早上前2堂: RNN X_Data = ['good', 'bad', 'worse', 'so g...