---
# System prepended metadata

title: '[ASP.NET] MVC Filter 整理'
tags: [ASP.NET, Filter, MVC]

---

# [ASP.NET] MVC Filter 整理


ASP.NET MVC 的 Filter 可以在 Request 進入 Controller 及執行 Action 的過程中執行特定邏輯，例如：權限驗證、錯誤攔截。

## Filter 類型
* **Authorization Filters**：進入 Controller 及執行 Action 之前執行驗證、授權判斷。
* **Action Filters**：在執行 Action 之前或之後，執行Filter邏輯。
* **Result Filter**：在執行 View 之前或之後，執行Filter邏輯。
* **Exception Filters**：處理未攔截的 Exception。

## 可設定Filter的位置

### 全域 Filter
在 Global.asax.cs 設定，MVC 專案在 Application_Start 中預設加入 [HandleError] Filter
* Global.asax.cs
```csharp=
protected void Application_Start()
{
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
```
進入 App_Start 中的 FilterConfig.cs 設定哪些 Filters 要在全域中被套用
* App_Start/FilterConfig.cs
```csharp=
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}
```
<font color="red"> 重要：若要啟用[HandleError]，需要將 Web.config 的 customErrors的mode改為On</font>
* Web.config
```xml=
<system.web>
    <customErrors mode="On" />
</system.web>
```
* 模擬例外錯誤
```csharp=
public class HomeController : Controller
{
    public ActionResult Index()
    {
        throw new Exception("Exception Test");
        return View();
    }
}
```

### Controller 套用 Filter
以下範例為在Controller中加上授權檢查的Filter，Controller中所有的Action都會套用授權檢查
```csharp=
[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}
```
### Action 套用 Filter
以下範例為在Index Action中加上快取Filter，設定快取保留時間為10秒
```csharp=
public class HomeController : Controller
 {
      [OutputCache(Duration=10)]
      public string Index()
      {
           return DateTime.Now.ToString("T");
      }
 }
```

## 自訂 Filter 
以網站請求 Controller 及 Action 的紀錄作為範例。

建立 Filter 資料夾，新增一個類別 MyLogFilter.cs，新增以下程式碼
* Filter/MyLogFilter.cs
```csharp=
public class MyLogFilter : ActionFilterAttribute, IActionFilter
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        ActionDescriptor descriptor = filterContext.ActionDescriptor;
        Log($"{descriptor.ControllerDescriptor.ControllerName}-{descriptor.ActionName}");
        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        base.OnResultExecuted(filterContext);
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        base.OnResultExecuting(filterContext);
    }

    private void Log(string content)
    {
        DateTime now = DateTime.Now;
        content = $"[{now.ToString("HH:mm:ss")}] {content}";
        string fileFullname = HttpContext.Current.Server.MapPath($"/Log/{now.ToString("yyyyMMdd")}_Trace.txt");
        File.AppendAllText(fileFullname, $"{content}\r");
    }
}
```

將 MyLogFilter 加入到全域 Filter 中
* App_Start/FilterConfig.cs
```csharp=
public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new MyLogFilter());
    }
}
```

說明：
 - 需要在專案下建立一個 Log 資料夾存放每天的紀錄
 - Log 方法會每天建立一個文字檔紀錄作為網站請求紀錄。
 ![](https://i.imgur.com/Hzrt8BH.jpg)

###### tags: `ASP.NET` `MVC` `Filter`

> 「卓越之人最大的優點是：在不利與艱難的遭遇裡百折不饒。」—貝多芬