필터 코어 ASP.NET MVC (필터)

  전에 코드를 실행하거나 ASP.NET MVC 필터의 특정 단계 후 실행 파이프 라인을 수 있습니다. 글로벌 될 수 있으며, 필터는 각 컨트롤러 또는 각각의 동작을 위해 구성 될 수있다.

1. 어떻게 작업을 필터링

  다른 필터 유형은 서로 다른 파이프 라인 단계에서 수행, 따라서 각각의 장면이있다. 요청 파이프 라인 작업을 수행하고있는 위치를 수행 생성되는 필터 타입을 선택할 필요가있다. MVC 작업에서 실행중인 필터 파이프 라인 통화, 때로는 MVC에서 수행 할 작업을 선택, 덕트 필터라고 같이, 필터 작업을 수행한다 :

  다른 필터는 파이프 라인의 다른 위치에서 수행합니다. 전용 파이프 라인 실행에 상기 전방 위치에 필터 등의 권한 필터. 도시 된 바와 같은 동작 (액션) 필터와 같은 다른 필터는, 전 파이프의 다른 부분의 실행 후에 수행 될 수있다 :

  

  필터를 선택합니다

  승인 요청 필터는 현재 사용자가 권한이 있는지 여부를 확인합니다.

  공간 필터는 인증 후의 제 처리 요구의 필터 및 필터를 빠져 나가는 파이프 요청 필터 요청 마지막 접촉이다. 성능의 측면에서, 필터에 특히 유용 캐싱 또는 단락 파이프 라인을 구현합니다.

  필터 패키지의 동작은 동작의 한 방법을 호출하고, 동작의 처리 파라미터 및 연산 결과의 복귀 동작에 전달 될 수있다.

  MVC 응용 프로그램 처리되지 않은 예외에 대한 예외 필터는 글로벌 정책을 적용 할 수 있습니다.

  단일 작업의 결과 결과는 필터를 포장하고, 성공적으로 실행할 수 있도록하는 작업을 수행 수행. 그들은 주위를 실행 실행 프로그램의 이상적인 또는 형식 논리적 뷰해야합니다.

  

  2. 필터를 구현

  동기 및 비동기 모든 필터는 다른 인터페이스 정의에서 지원하는 얻을 수 있습니다. 작업의 종류에 실시하기에 따르면, 동기 또는 비동기 구현을 선택합니다. 보기의 프레임의 관점에서, 그들은 교환 할 수있다.

  동기화 필터 OnStageExecuting 및 OnStageExecuted 방법을 정의 (예외가 있습니다). OnStageExecuting 방법은 이벤트 파이프 라인 단계 전에 무대에 이름에 의해 호출되며, OnStageExecuted 방법은 후라는 이름의 파이프 라인 단계의 단계 이후에 호출됩니다.

    public class SampleActionFilter:IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //操作执行前做的事情
        }
        public void OnActionExecuted(ActionExecutedContext context)
        {
            //操作执行后做的事情
        }
    }

  异步过滤器定义了一个单一的 OnActionExecutionAsync  方法,可以在具体管道阶段的前后运行。 OnActionExecutionAsync 方法提供了一个 ActionExecutionDelegate 委托,调用时该委托会执行具体管道阶段的工作,然后等待完成。

public class SampleAsyncActionFilter: IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //操作执行前做的事情
            await next();
            //操作执行后做的事情
        }
    }

  

  3.过滤器作用域

  过滤器有三种不同级别的作用域。你可以在特定的操作上用特性(Attribute)的方式使用特定的过滤器。也可以在控制器上用特性的方式使用过滤器,这样就可以将效果作用在控制器内的所有操作上。或者注册一个全局过滤器,它将作用于整个 MVC 应用程序的每一个操作。

  如果想要使用全局过滤器,可以在配置 MVC 时,在 Startup 的 ConfigureServices 方法中添加:

services.AddMvc(options =>
            {
                options.Filters.Add(typeof(SampleActionFilter));//通过类型
                options.Filters.Add(new SampleActionFilter());//注册实例
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

  过滤器既可以通过类型添加,也可以通过实例添加。如果通过实例添加,则该实例会被使用于每一个请求。如果通过类型添加,则在每次请求后都会创建一个实例,其所有构造函数依赖项都将通过 DI 来填充。

  把过滤器接口的实现当作特性使用也非常方便。过滤器特性可应用于控制器和操作方法。框架包含了内置的基于特性的过滤器,可以继承他们或者另外定制。例如,下面的过滤器继承了 ResultFilterAttribute,并重写 OnResultExecuting 方法(在响应中增加一个信息头):

  

public class AddHeaderAttribute: ResultFilterAttribute
    {
        private readonly string _name;
        private readonly string _value;

        public AddHeaderAttribute(string name, string value)
        {
            _name = name;
            _value = value;
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                _name,new string[] { _value });
            base.OnResultExecuting(context);
        }
    }

  特性允许过滤器接受参数,如下,可将此特性添加到控制器或操作中,并为其指定所需 HTTP 头的名称和值:

[AddHeader("Author", "Ruby Lu")]
 public class HomeController : Controller
{
}

  以下几种过滤器接口可以自定义为相应特性的实现:

    ActionFilterAttribute

    ExceptionFilterAttribute

    ResultFilterAttribute

    FormatFilterAttribute

    ServiceFilterAttribute

    TypeFilterAttribute

 

  4.取消和短路

  通过设置传入过滤器方法的上下文参数中的 Result 属性,可以在过滤器管道的任意一点短路管道。比如,下面的 ShortCircuitingResourceFilter 将阻止它之后管道内的所有过滤器,包括所有操作过滤器:

public class ShortCircuitingResourceFilter:Attribute,IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.Result = new ContentResult() {
                Content = "短路"
            };
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {

        }
    }

 

2.配置过滤器

  全局过滤器在 Startup 中配置。基于特性的过滤器如果不需要任何依赖,可以简单地继承一个已存在地过滤器相对应地特性类型。如果要创建一个非全局作用域,但需要从依赖注入中获得依赖项的过滤器,那么在它们上面加上 ServiceFilterAttribute 或 TypeFilterAttribute 特性,这样就可用于控制器或操作了。

  1.依赖注入

  以特性形式实现的,直接添加到控制器或操作的过滤器,其构造函数不得由依赖注入提供依赖项。其原因在于,特性所需的构造函数参数必须由使用处直接提供。这是特性原型机理的限制。

  如果过滤器需要从 DI 中获得依赖项,那么可以用以下几种方法在类或操作方法使用:

    ServiceFilterAttribute

    TypeFilterAttribute

    IFilterFactory 实现特性

  TypeFilter 将为其依赖项从 DI 中使用服务来实例化一个实例。 ServiceFilter 则从 DI 中获取一个过滤器实例。下面演示 ServiceFilter:

  先在 ConfigureServices 中注册 AddHeaderFilterWithDI 类型:services.AddScoped<AddHeaderFilterWithDI>(); 

  然后使用:

    [ServiceFilter(typeof(AddHeaderFilterWithDI))]

    public IActionResult Index()

    {  

    }

  ServiceFilterAttribute 实现了IFilterFactory 接口,它公开了一个创建 IFilter 实例的方法。在 ServiceFilterAttribute 中,IFilterFactory 接口的 CreateInstance 方法被实现为从服务容器加载指定的类型。

  TypeFilterAttribute 非常类似 ServiceFilterAttribute (也实现 IFilterFactory 接口),但它的类型不是直接从 DI 容器中解析,相反,它使用 Microsoft.Extensions.DependencyInjection.ObjectFactory 实例化类型。

  由于这种差异,使用 TypeFilterAttribute 引用的类型不需要在使用前向容器注册,但它们仍由容器来填充其依赖项。此外,TypeFilterAttribute 可以可选的接受该类型的构造函数参数。下面是 TypeFilterAttribute 演示:

        [TypeFilter(typeof(AddHeaderAttribute),Arguments =new object[] { "Author","Ruby" })]
        public IActionResult Index()
        {
            return View();
        }

   如果有一个简单的过滤器,不需要任何参数,但有构造函数需要通过 DI 填充依赖项,那么可以继承 TypeFilterAttribute,允许使用自己命名的特性类和方法(而不是 [TypeFilterAttribute(typeof(FilterType))])。下面的过滤器显示了如何实现此功能:

 public class SampleActionFilterAttribute:TypeFilterAttribute
    {
        public SampleActionFilterAttribute() : base(typeof(SampleActionFilterImpl))
        {
        }
        private class SampleActionFilterImpl:IActionFilter
        {
            public void OnActionExecuting(ActionExecutingContext context)
            {
                //操作执行前做的事情
            }
            public void OnActionExecuted(ActionExecutedContext context)
            {
                //操作执行后做的事情
            }
        }
    }

  该过滤器可通过使用 [SampleActionFilter] 这样的语法应用于类或方法,而不必使用 [TypeFilter] 或 [ServiceFilter] 。

  IFilterFactory 实现 IFilter ,因此在过滤器管道中,任何位置的  IFilterFactory 实例都可当作 Filter 实例来使用。当框架准备调用过滤器时,将尝试将其转换为 IFilterFactory 。如果转换成功, 则调用 CreateInstance 方法来创建将被调用的 IFilter 实例。这是一种非常灵活的设计,因为当应用程序启动时,不需要明确地设置精确地过滤器。

  你可以在自己地特性中实现 IFilterFactory 几口,作为另一种创建过滤器的方法:

public class AddHeadWithFactoryAttribute:Attribute, IFilterFactory
    {
        public bool IsReusable { get; }
        //实现IFilterFactory
        public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
        {
            return new InternalAddHeaderFilter();
        }
    }

    public class InternalAddHeaderFilter : IResultFilter
    {
        public  void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "Internal", new string[] { "Header Add" });
        }
        public void OnResultExecuted(ResultExecutedContext context)
        {

        }
    }

 

  2.排序

   过滤器可以应用于操作方法或控制器(通过特性)或添加到全局过滤器集合中。作用域通常也决定了排序,最接近操作的过滤器首先运行。

  除了作用域,过滤器还可以通过实现 IOrderedFilter 来重写它们的执行顺序。此接口简单的暴露了一个 int Order 属性,并且过滤器基于该属性以数字升序执行。所有内置的过滤器,包括 TypeFilterAttribute 和 ServiceFilterAttribute ,都实现 IOrderedFilter  接口。,因此当将过滤器特性应用于类或方法时,可以指定过滤器执行顺序。默认情况下,所有内置过滤器的 Order 属性都为0,因此范围用作分隔符,并且是决定性因素(除非 Order 设置为 0)。

  每个从 Controller 基类继承的控制器都包含 OnActionExecuting 和 OnActionExecuted 方法。这些方法为给定操作包装了过滤器,它们分别最先运行和最后运行。假设没有为任何过滤器设置 Order 舒总,那么单纯基于范围的顺序为:

  控制器的 OnActionExecuting

  全局过滤器的OnActionExecuting

  类过滤器的OnActionExecuting

  方法过滤器的OnActionExecuting

  方法过滤器的OnActionExecuted 

  类过滤器的OnActionExecuted 

  全局过滤器的OnActionExecuted 

  控制器过滤器的OnActionExecuted 

   

  要修改默认的基于范围的顺序,则应显示设置类级别或者方法级别过滤器的 Order 属性。例如,将 Order = -1 添加到方法级属性:

  [MyFilter (Name = "...",Order = -1)]

  在这种情况下,小于零的值将确保此过滤器在全局和类级过滤器之前运行:

  控制器的 OnActionExecuting

  方法过滤器的OnActionExecuting

  全局过滤器的OnActionExecuting

  类过滤器的OnActionExecuting

  类过滤器的OnActionExecuted 

  全局过滤器的OnActionExecuted 

  控制器过滤器的OnActionExecuted 

  方法过滤器的OnActionExecuted 

  Controller 类的方法总是在所有过滤器之前和之后运行。这些方法不作为IFilter实例实现。也不参与IFilter排序算法。

 

  3.对比中间件

  一般来说,过滤器用于处理业务与应用程序的横切关注点,用法和功能很像中间件,但过滤器允许你将作用范围缩小,并将其插入到应用程序中有意义的位置,例如视图之前或模型绑定之后。过滤器是 MVC 的一部分,可以访问其上下文和构造函数。例如,中间件很难检测到请求的模型验证是否产生错误,并且做出相应的响应。

 

추천

출처www.cnblogs.com/afei-24/p/11334100.html