ASP.NET Core 過濾器

過濾器

過濾器與中間件很相似,能夠在某些功能前後執行,由此而形成一個管道

ASP.NET Core MVC 提供了5種類型的過濾器

  • AuthorizationFilter:最先執行,用於判斷用戶是否授權如果未授權直接結束當前請求
  • ResourceFilter:在Authorization後執行,可以用來對請求判斷是否執行Action
  • ActionFilter:在Action執行的前後執行,與Resource不同的是,它在模型綁定之後執行。
  • ExceptionFilter:用於捕獲異常
  • ResultFilter:在最後執行,可以控制Action執行的結果

以上五種類型過濾器的工作順序

graph TD
A[中間件] –> B[AuthorizationFilter]
B –> C[ResourceFilter]
C –> D[ExceptionFilter]
D –> F[模型綁定]
F –> G[ActionFilter]
G –> H[Action]
H –> I[ActionFilter]
I –> L[ResultAction]

快速入門

Action過濾器將在Controller的Action執行之前和執行相應的方法

首先我們新建一個類,繼承於IActionFilter,查看IActionFilter裡面會發現有兩個介面

 //
    // 摘要:
    //     A filter that surrounds execution of the action.
    public interface IActionFilter : IFilterMetadata
    {
        //
        // 摘要:
        //     Called after the action executes, before the action result.
        //
        // 參數:
        //   context:
        //     The Microsoft.AspNetCore.Mvc.Filters.ActionExecutedContext.
        void OnActionExecuted(ActionExecutedContext context);
        //
        // 摘要:
        //     Called before the action executes, after model binding is complete.
        //
        // 參數:
        //   context:
        //     The Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.
        void OnActionExecuting(ActionExecutingContext context);
    }

根據描述我們可得知第一個是在執行方法之後執行,第二個在執行方法之前執行

然後就可以寫我們自己的過濾器啦

    public class TestActionFilterAttribute : Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine("OnActionExecuted執行了");
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine("OnActionExecuting執行了");
        }
    }

心細的小夥伴可能看到我這裡還繼承了Attribute,沒錯可以直接通過特性應用在方法或者類上表示對這個方法或者類進行過濾

[HttpGet]
[TestActionFilter]
public IActionResult Test()
{
    Console.WriteLine("Action執行");
    return Ok(new
    {
        msg = "OK"
    });
}
[Route("api/[controller]")]
[ApiController]
[TestActionFilter]
public class TestController : ControllerBase
{
}

也可以在startupConfigureServices()裡面進行添加,表示全局註冊

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
        options.Filters.Add(new WebApplication2.Utility.Filter.TestActionFilterAttribute()));
}

執行結果

OnActionExecuting執行了
Action執行
OnActionExecuted執行了

多個過濾器執行時,會保持著先進後出的原則,例如

public class TestActionFilterAttribute : Attribute, IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        Console.WriteLine("OnActionExecuted1執行了");
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        Console.WriteLine("OnActionExecuting1執行了");
    }
}
public class TestActionFilterAttribute2 : Attribute, IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        Console.WriteLine("OnActionExecuted2執行了");
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        Console.WriteLine("OnActionExecuting2執行了");
    }
}

執行結果為

OnActionExecuting1執行了
OnActionExecuting2執行了
Action執行
OnActionExecuted2執行了
OnActionExecuted1執行了

除了直接實現Filter介面,.Net Core同時提供了一些基於特性的過濾器,我們可以繼承相應的特性來實現自定義的過濾器。這些特性包括ActionFilterAttributeExceptionFilterAttributeResultFilterAttributeFormatFilterAttributeServiceFilterAttributeTypeFilterAttribute

Filter通過註解的話如何注入實例呢

如果特性類的構造函數有參的話特性也是需要帶入參數的並且只能是常量,那麼如何注入呢?

  1. ServiceFilter 需要在容器中註冊過濾器
[ServiceFilter(typeof(TestActionFilterAttribute))]
  1. TypeFilter 通過使用Microsoft.Extensions.DependencyInjection.ObjectFactory對指定的過濾器類型進行實例化因此不需要註冊容器
 [TypeFilter(typeof(TestActionFilterAttribute))]
  1. IFilterFactory 需要自己手動實現工廠類(其實就是第一種的實現方式,也需要在容器中註冊過濾器)
public class CustomFilterFactory : Attribute,IFilterFactory
{
    private Type _filterType = null;
    public CustomFilterFactory(Type type)
    {
        this._filterType = type;
    }
    public bool IsReusable => true;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
       return (IFilterMetadata)serviceProvider.GetService(this._filterType);
      //  throw new NotImplementedException();
    }
}
Tags: