[鐵人賽Day17] ASP.Net Core MVC 進化之路 - Filter

Filter延續了ASP.Net MVC5的設計,

可在各Pipeline執行前與執行後指定需觸發的事件,

本文將介紹ASP.Net Core Filter的使用方式。

 

 

ASP.Net Core中預設有五種Filter:

  1. Authorization Filter
  2. Resource Filter
  3. Action Filter
  4. Exception Filter
  5. Result Filter

要求處理會歷經授權篩選條件、資源篩選條件、模型繫結、動作篩選條件、動作執行和動作結果轉換、例外狀況篩選條件、結果篩選條件,以及結果執行。(圖片來源:MSDN)

 

在執行優序上,

Authorization Filter >Resource Filter >Exception Filter >Action Filter >Result Filter 

所以如果是在Authorization Filter 、Resource Filter 階段發生錯誤,

則無法被Exception Filter捕捉(要自訂錯誤處理方式)。

 

Filter Attribute可以在三個地方宣告,

  • Startup:執行範圍為全域(Global)
  • Controller:執行範圍為Controller本身
  • Action:執行範圍為Action本身

在執行順序上,

Startup >Controller >Action

雖然可以透過Order自訂順序,

但筆者個人認為正常使用下不太會用到,

如果有需要的讀者可參考MSDN

 

Authorization Filter

Authorization可以處理跟授權相關的邏輯,

而授權的方式有很多種,

如簡單型授權、角色授權、宣告式授權等。

當系統功能需要依據某種條件賦予使用權力時,

使用Authorization Filter會是個不錯的用法(你也可以自訂Middleware)。

 

礙於授權本身範疇較大,

筆者將於後面文章中進行更詳細的說明。

 

Resource Filter

Resource Filter可以依據自訂的條件,

決定是否繼續後面的流水線(Pipeline),

達到為網站節省資源的目的。

使用時必須實作 IResourceFilter 或 IAsyncResourceFilter 介面。

OnResourceExecuting 表Request in的Pipeline,

OnResourceExecuted 介面則代表Response out。

 

官方提供的使用時機為限制檔案上傳大小

這情境雖然簡單但還蠻實用的,

我們迅速的來實作一個IResourceFilter 。

如果要使用Attribute的形式則必須要實作Attribute 。

public class AllowFileSizeAttribute : Attribute, IResourceFilter
{
    private long maxSize;

    public AllowFileSizeAttribute(long _maxSize)
    {
        this.maxSize = _maxSize;
    }

    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var contentLength = context.HttpContext.Request.ContentLength;
        if (contentLength > maxSize)
        {
            context.Result = new ContentResult()
            {
                Content = $"You can't upload file size over {maxSize / 1024}KB."
            };
        }

    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
         
    }
}

 

前端程式碼

我們在任意View中新增一個上傳表單,

請注意一定要給name 不然後端會認不得!

<form asp-action="Create" enctype="multipart/form-data">
    <div class="form-group">
        <label class="control-label">檔案上傳</label>
        <input type="file" class="form-control" name="file" />
    </div>

    <div class="form-group">
        <input type="submit" value="Create" class="btn btn-default" />
    </div>
</form>

 

最後在Action中掛上小巧玲瓏的Attribute,

我們設定檔案大小不得超過2048B(=2KB)。

[AllowFileSize(2048)]
[HttpPost]
public IActionResult Create()
{
           
    return View();
}

 

使用Debug模式觀察檔案大小。

 

測試結果

 

Action Filter & Result Filter

ActionFilter同步非同步兩種版本 - IActionFilter 、 IAsyncActionFilter

執行前執行後可分 OnActionExecuting 、 OnActionExecuted兩種方法,

主要可處理輸入值(After ModelBinding)或Controller Context相關結果。

也可直接指定回傳的Result(後面優序的Filter就不會被觸發)。

官方提供範例為處理ModelState驗證結果

 

ResultFilter一樣有 IResultFilter 、 IAsyncResultFilter 兩種版本。

執行前執行後可分 OnResultExecuting 、 OnResultExecuted兩種方法,

 OnResultExecuted會在回傳Response後呼叫,

所以若有跟Response相關的操作請在 OnResultExecuting中處理。

 

官方有提供ActionFilterAttribute類別,

內容涵蓋了ActionFilter及ResultFilter兩種,

大家可依個人需求搭配使用。

Exception Filter

實作 IExceptionFilter 或 IAsyncExceptionFilter 可自訂Exception Filter,

官方提供範例為自訂開發環境錯誤頁面

Exception Filter能捕捉的範圍如下:

  • Model Binding Exception
  • Controller Invoke Exception
  • Action Filter & Result Filter Exception

 

筆者將於後面獨立一篇介紹Exception Filter與Exception Middleware的使用差異。

 

結語

自從Middleware出來之後Filter好像就有點被遺棄無力(咦?),

雖然筆者比較推Middleware的設計方式(彈性),

不過Filter還是很好用啦XD,

如果文章內容有誤的再麻煩指正,謝謝!

 

參考

https://docs.microsoft.com/zh-tw/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.1#resource-filters