ASP.NET Core 2 學(xué)習(xí)筆記(十四)Filters

Filter是延續(xù)ASP.NET MVC的產(chǎn)物,同樣保留了五種的Filter,分別是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。
通過不同的Filter可以有效處理封包進出的加工,本篇將介紹ASP.NET Core的五種Filter運作方式。

Filter 介紹

Filter的作用是在Action 執(zhí)行前或執(zhí)行后做一些加工處理。
某種程度來看,會跟Middleware很像,但執(zhí)行的順序略有不同,用對Filter不僅可以減少代碼,還可以提高執(zhí)行效率。
ASP.NET Core 有以下五種Filter 可以使用:

  • Authorization Filter
    Authorization是五種Filter中優(yōu)先級最高的,通常用于驗證Request合不合法,不合法后面就直接跳過。
  • Resource Filter
    Resource是第二優(yōu)先,會在Authorization之后,Model Binding之前執(zhí)行。通常會是需要對Model加工處理才用。
  • Action Filter
    最常使用的Filter,封包進出都會經(jīng)過它,使用上沒什么需要特別注意的。跟Resource Filter很類似,但并不會經(jīng)過Model Binding。
  • Exception Filter
    異常處理的Filter。
  • Result Filter
    當(dāng)Action完成后,最終會經(jīng)過的Filter。

Filter 運作方式
ASP.NET Core的每個Request都會先經(jīng)過已注冊的Middleware接著才會執(zhí)行Filter,除了會依照上述的順序外,同類型的Filter預(yù)設(shè)都會以先進后出的方式處里封包。
Response在某些Filter并不會做處理,會直接被pass。Request及Response的運作流程如下圖:

  • 黃色箭頭是正常情況流程
  • 灰色箭頭是異常處理流程

建立Filter
ASP.NET Core的Filter基本上跟ASP.NET MVC的差不多。
上述的五種Filter范例分別如下:
Authorization Filter
AuthorizationFilter.cs


using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

 namespace MyWebsite.Filters
{

    public class AuthorizationFilter : IAuthorizationFilter
    {

        public void OnAuthorization(AuthorizationFilterContext context)

        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }
    }
}

非同步的方式:


// ...

public class AuthorizationFilter : IAsyncAuthorizationFilter

{

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)

    {

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

    }

}

Resource Filter
ResourceFilter.cs


using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyWebsite.Filters
{

    public class ResourceFilter : IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }

 

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:


// ...

public class ResourceFilter : IAsyncResourceFilter
{
    public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
    {
        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        await next();
        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

Action Filter
ActionFilter.cs


using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Mvc.Filters;

 

namespace MyWebsite.Filters

{

    public class ActionFilter : IActionFilter

    {

        public void OnActionExecuting(ActionExecutingContext context)

        {

            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        }

 

        public void OnActionExecuted(ActionExecutedContext context)

        {

            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");

        }

    }

}

非同步的方式:


// ...

public class ActionFilter : IAsyncActionFilter

{

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

    {

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

 

        await next();

 

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");

    }

}

Result Filter
ResultFilter.cs


using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Mvc.Filters;

 

namespace MyWebsite.Filters

{

    public class ResultFilter : IResultFilter

    {

        public void OnResultExecuting(ResultExecutingContext context)

        {

            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        }

 

        public void OnResultExecuted(ResultExecutedContext context)

        {

            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");

        }

    }

}

非同步的方式:


// ...

public class ResultFilter : IAsyncResultFilter

{

    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)

    {

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

 

        await next();

 

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");

    }

}

Exception Filter
ExceptionFilter.cs


using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Mvc.Filters;

 

namespace MyWebsite.Filters

{

    public class ExceptionFilter : IExceptionFilter

    {

        public void OnException(ExceptionContext context)

        {

            context.ExceptionHandled = true; // 表明異常已處理,客戶端可得到正常返回

            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        }

    }

}

非同步的方式:


// ...

public class ExceptionFilter : IAsyncExceptionFilter

{

        public Task OnExceptionAsync(ExceptionContext context)

        {

            context.ExceptionHandled = true;// 表明異常已處理,客戶端可得到正常返回

            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

            return Task.CompletedTask;

        }

}

注冊Filter
Filter有兩種注冊方式,一種是全局注冊,另一種是用[Attribute]局部注冊的方式,只套用在特定的Controller或Action。
全局注冊
在Startup.ConfigureServices的MVC服務(wù)中注冊Filter,這樣就可以套用到所有的Request。如下:


// ...

public class Startup

{

    public void ConfigureServices(IServiceCollection services)

    {

        services.AddMvc(config =>

        {

            config.Filters.Add(new ResultFilter());

            config.Filters.Add(new ExceptionFilter());

            config.Filters.Add(new ResourceFilter());

        });

    }

}

局部注冊
ASP.NET Core在局部注冊Filter的方式跟ASP.NET MVC有一點不一樣,要通過[TypeFilter(type)]。
在Controller或Action上面加上[TypeFilter(type)]就可以局部注冊Filter。如下:


// ...

namespace MyWebsite.Controllers

{

    [TypeFilter(typeof(AuthorizationFilter))]

    public class HomeController : Controller

    {

        [TypeFilter(typeof(ActionFilter))]

        public void Index()

        {

            Response.WriteAsync("Hello World! \r\n");

        }

         

        [TypeFilter(typeof(ActionFilter))]

        public void Error()

        {

            throw new System.Exception("Error");

        }

    }

}

[TypeFilter(type)]用起來有點冗長,想要像過去ASP.NET MVC用[Attribute]注冊Filter的話,只要將Filter繼承Attribute即可。如下:


public class AuthorizationFilter : Attribute, IAuthorizationFilter

{

    // ...

}

public class ActionFilter : Attribute, IActionFilter

{

    // ...

}

[Attribute] 注冊就可以改成如下方式:


// ...

namespace MyWebsite.Controllers

{

    [AuthorizationFilter]

    public class HomeController : Controller

    {

        [ActionFilter]

        public void Index()

        {

            Response.WriteAsync("Hello World! \r\n");

        }

         

        [ActionFilter]

        public void Error()

        {

            throw new System.Exception("Error");

        }

    }

}

執(zhí)行結(jié)果
http://localhost:5000/Home/Index 輸出結(jié)果如下:


AuthorizationFilter in.

ResourceFilter in.

ActionFilter in.

Hello World!

ActionFilter out.

ResultFilter in.

ResultFilter out.

ResourceFilter out.

http://localhost:5000/Home/Error 輸出結(jié)果如下:


AuthorizationFilter in.

ResourceFilter in.

ActionFilter in.

ActionFilter out.

ExceptionFilter in.

ResourceFilter out.

執(zhí)行順序
預(yù)設(shè)注冊同類型的Filter 是以先進后出的方式處里封包,注冊層級也會影響執(zhí)行順序。


但也可以通過實現(xiàn) IOrderedFilter 更改執(zhí)行順序。例如:


public class ActionFilter : Attribute, IActionFilter, IOrderedFilter

{

    public string Name { get; set; }

 

    public int Order { get; set; } = 0;

 

    public void OnActionExecuting(ActionExecutingContext context)

    {

        context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) in. \r\n");

    }

    public void OnActionExecuted(ActionExecutedContext context)

    {

        context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) out. \r\n");

    }

}

在注冊Filter 時帶上Order,數(shù)值越小優(yōu)先權(quán)越高。

public class Startup

{

    public void ConfigureServices(IServiceCollection services)

    {

        services.AddMvc(config =>

        {

            config.Filters.Add(new ActionFilter() { Name = "Global", Order = 3 });

        });

    }

}
namespace MyWebsite.Controllers

{

    [ActionFilter(Name = "Controller", Order = 2)]

    public class HomeController : Controller

    {

        [ActionFilter(Name = "Action", Order = 1)]

        public void Index()

        {

            Response.WriteAsync("Hello World! \r\n");

        }

    }

}

變更執(zhí)行順序后的輸出內(nèi)容:


ActionFilter(Action) in. 

ActionFilter(Controller) in. 

ActionFilter(Global) in. 

Hello World! 

ActionFilter(Global) out. 

ActionFilter(Controller) out. 

ActionFilter(Action) out.

參考

ASP.NET Core Filters

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容