iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
1
Modern Web

我與 ASP.NET Core 的 30天系列 第 14

[Day14] Filters - 我與 ASP.NET Core 3 的 30天

  • 分享至 

  • xImage
  •  

ASP.NET Core中的Filter可以讓程式碼在Request pipeline中的特定階段之前或之後執行
Filter用起來跟 Middleware 有點相似,

ASP.NET Core 預設有五種Filter,分別是:

  • Authorization Filter
    第一個執行,用來處理授權邏輯,驗證Request是否合法,如果Request沒有經過授權,就會跳過後面。
  • Resource Filter
    接在Authorization Filter之後,通常用來處理快取或是模型繫結。
  • Action Filter
    封包進出都會經過,通常用來處理傳入 Action 的參數和回應的結果。
  • Exception Filter
    處理例外的Filter
  • Result Filter
    Action處理完畢之後,最後就會經過Result Filter

ASP.NET Core的每個Request都會先通過Middleware之後才會進入Filter,進入Filter之後的流程如下圖

https://ithelp.ithome.com.tw/upload/images/20200928/20129389v69eTef6yj.png
圖片來源:MSDN

自定義Filter

接下來示範如何自訂義Filter

ActionFilter

實作 IActionFilter 或 IAsyncActionFilter 介面。
執行會包圍Action的執行。

建立SampleActionFilter.cs,並加入以下內容

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FilterSample.Filters
{
    //同步
    public class SampleActionFilter : Attribute ,IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync("Sample Action in \r\n");
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync("Sample Action out \r\n");
        }
    }
    
    //非同步
    public class SampleAsyncActionFilter : Attribute, IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            await context.HttpContext.Response.WriteAsync("Async Sample Action in \r\n");

            var resultContext = await next();
            
            await context.HttpContext.Response.WriteAsync("Async Sample Action out \r\n");
        }
    }
}

ActionExecutingContext 提供下列屬性:

  • ActionArguments -啟用讀取Action的輸入。
  • Controller - 提供對控制器執行個體的管理。
  • Result - 設定 Result 會縮短Ation和後續動作Filter的執行。

OnActionExecuting 動作篩選條件可以用來:

  • 驗證模型狀態。
  • 如果狀態無效,則傳回錯誤。
    注意:在Controller加上屬性[ApiController]會自動驗證模型狀態,並回傳Http 400。

OnActionExecuted 方法會在動作方法之後執行:

  • 並可以透過 Result 屬性查看及操作動作的結果。
  • Canceled 會在動作執行被另一個篩選條件縮短時被設為 true。
  • Exception 會在動作或後續的動作篩選條件擲回例外狀況時被設為非 Null 值。

ResourceFilter

實作 IResourceFilter 或 IAsyncResourceFilter 介面。
執行會包裝大部分的篩選條件管線。
只有AuthorizationFilter會在ResourceFilter之前執行。

SampleResourceFilter.cs

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FilterSample.Filters
{
    public class SampleResourceFilter : Attribute ,IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync("Sample Resource in \r\n");
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync("Sample Resource out \r\n");
        }
    }
    
    public class SampleAsyncResourceFilter : Attribute, IAsyncResourceFilter
    {
        public async Task OnResourceExecutionAsync(
            ResourceExecutingContext context,
            ResourceExecutionDelegate next)
        {
            await context.HttpContext.Response.WriteAsync("Async Sample Resource in \r\n");

            var resultContext = await next();
            
            await context.HttpContext.Response.WriteAsync("Async Sample Resource out \r\n");
        }
    }
}

ResourceFilter很適合用來縮短大部分的pipeline。比方說,caching filter可以避免快取後其餘pipeline繼續執行。

ResultFilter

實作介面:
IResultFilter 或 IAsyncResultFilter
IAlwaysRunResultFilter 或 IAsyncAlwaysRunResultFilter
執行會包圍Action的執行。

SampleResultFilter.cs

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FilterSample.Filters
{
    public class SampleResultFilter : Attribute ,IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            // Do something before the Result executes.
            context.HttpContext.Response.WriteAsync("Sample Result in \r\n");
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync("Sample Result out \r\n");
        }
    }
    
    public class SampleAsyncResultFilter : Attribute, IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(
            ResultExecutingContext context,
            ResultExecutionDelegate next)
        {
            await context.HttpContext.Response.WriteAsync("Async Sample Result in \r\n");

            var resultContext = await next();
            
            await context.HttpContext.Response.WriteAsync("Async Sample Result out \r\n");
        }
    }
}

ResultFilter只會在Action或ActionFilter產生動作結果時執行。當下列情況時,不會執行ResultFilter:
AuthorizationFilter或ResourceFilter會對pipeline行較短的線路。
ExceptionFilter會產生ActionResult來處理例外狀況。

上列的範例因為繼承了Attribute類別,所以可以用Attribute的方式套用在Action或是Controller上
例如:

namespace FilterSample.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class FilterDemoController : ControllerBase
    {
        [SampleAsyncActionFilter]
        [HttpGet]
        public void Get()
        {
            Response.WriteAsync("Action in! \r\n");
        }
    }
}

輸出的結果就會為
Async Sample Action in
Action in!
Async Sample Action out


上一篇
[Day13] CORS 跨來源資源共用 - 我與 ASP.NET Core 3 的 30天
下一篇
[Day15] 例外事件處理 - 我與 ASP.NET Core 3 的 30天
系列文
我與 ASP.NET Core 的 30天31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言