過濾器 過濾器(Filter)把附加邏輯註入到MVC框的請求處理,實現了交叉關註。所謂交叉關註(Cross-Cutting Concerns),是指可以用於整個應用程式,而又不適合放置在某個局部位置的功能,否則會打破關註分離模式。典型的例子有:登錄、授權、緩存等等。 使用過濾器 如果希望動作方法只能 ...
過濾器
過濾器(Filter)把附加邏輯註入到MVC框的請求處理,實現了交叉關註。所謂交叉關註(Cross-Cutting Concerns),是指可以用於整個應用程式,而又不適合放置在某個局部位置的功能,否則會打破關註分離模式。典型的例子有:登錄、授權、緩存等等。
使用過濾器
如果希望動作方法只能被認證用戶所使用,可以在每個動作方法中檢查請求的授權狀態。如在動作方法中使用Request.IsAuthenticated方法明確地檢查授權:if(!Request.IsAuthenticated){如果未被授權,則…}。
但是,如果在項目中這麼做,那會非常繁瑣,他需要在每一個需要有授權認證的動作方法中進行判斷。所以,採用過濾器才是最好的辦法,如清單1:
// 說明: // 過濾器是 .NET 的註解屬性,可以把它們運用於動作方法或控制器類。 // 當被用於控制器類時,其作用效果將覆蓋當前控制器中的每一個方法。 [Authorize] public class AdminController : Controller { public ViewResult Index() { … } public ViewResult Edit(int productId) { … } }
.NET的註解屬性,一個新鮮的事物
註解屬性(Attribute)是派生於System.Attribute的特殊的.NET類。它們可以被附加到其他代碼元素上,包括類、方法、屬性以及欄位等。目的是把附加信息嵌入到已編譯的代碼中,以便在運行時讀回這些信息。
在C#中,註解屬性用方括弧進行附加,而且可以用已命名參數語法給它們的public屬性賦值(如:[MyAttribute(SomeProperty=value)])。在C#的編譯器命名約定中,如果這些註解屬性類的名稱以單詞Attribute結尾,則可以忽略這一部分(如,對於AuthorizeAttribute註解屬性,可以寫成[Authorize])。
過濾器的四種基本類型
MVC框架支持四種不同類型的過濾器。分別是:認證過濾器、動作過濾器、結果過濾器、異常過濾器,如下表:
過濾器類型 |
介面 |
預設實現 |
描述 |
Authorization (認證過濾器) |
IAuthorizationFilter |
AuthorizeAtrribute |
最先運行,在任何其他過濾器或動作方法之前 |
Action (動作過濾器) |
IActionFilter |
ActionFilterAtrribute |
在動作方法之前及之後運行 |
Result (結果過濾器) |
IResultFilter |
ActionFilterAtrribute |
在動作結果被執行之前和之後運行 |
Exception (異常過濾器) |
IExceptionFilter |
HandleErrorAtrribute |
僅在另一個過濾器、動作方法、或動作結果拋出異常時運行 |
在框架調用一個動作之前,會首先檢測該方法的定義,以查看它是否具有這些過濾器設置。如果有,那麼便會在請求管道的相應點上調用這些介面所定義的方法。當然,框架預設實現了這些介面。
註:ActionFilterAtrribute類即實現了IActionFilter,也實現了IResultFilter介面,但這是一個抽象類,要求我們必須提供一個實現。
將過濾器運用於控制器和動作方法
過濾器可以應用於動作方法,也可以運用於整個控制器。清單1,將Authorize過濾器運用於AdminController類,其效果與將其運用於控制器中的每一個方法相同,如清單2:
public class AdminController : Controller { [Authorize] public ViewResult Index() { … } [Authorize] public ViewResult Edit(int productId) { … } }
可以運用多個過濾器,也可以混搭它們運用的層級——即,將它們運用於整個控制器或某個動作方法。如清單3演示了三個不同過濾器的使用方式:
[Authorize(Roles="trader")] // applies to all actions(運用於所有動作) public class ExampleController : Controller { [ShowMessage] // applies to just this action(僅用於本動作) [OutputCache(Duration=60)] // applies to just this action(僅用於本動作) public ViewResult Index() { … } }
註:如果為控制器定義了一個自定義基類,那麼運用於基類上的任何過濾器都會影響其派生類。
創建示例項目
為了後面內容的介紹,我們這裡利用空模板創建一個名為Filters的項目。在項目中添加一個Home控制器,並將其Index動作方法修改成如下這樣:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Controllers { public class HomeController : Controller { /// <summary> /// 一個返回字元串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字元串值發送給瀏覽器 /// (這隻是為了簡化,在實際的項目中還是應該使用視圖——這裡只關註控制器) /// </summary> /// <returns></returns> public string Index() { return "This is the Index action on the Home Controller"; } } }
上面的動作方法的返回值修改為字元串型,這樣可以是MVC框架繞過Razor視圖引擎,直接將字元串發送給瀏覽器,這樣做只是為了簡化,因為現在我們只關註控制器。
該示例的運行結果如圖所示:
使用授權過濾器
授權過濾器是首先運行的過濾器,而且也在動作方法被調用之前。過濾器通過執行設定的授權策略以確保動作方法只被一人在用戶所調用。授權過濾器需要實現IAuthorizationFilter介面。如:
namespace System.Web.Mvc { public interface IAuthorizationFilter { void OnAuthorization(AuthorizationContext filterContext); } }
當然也可以通過創建實現IAuthorizationFilter介面的類,實現一個自定義的授權過濾器,使用自己的安全邏輯。但是,不建議這樣做,主要原因如下:
警告:編寫安全性代碼的安全性
一般情況下,自行編寫的安全代碼總會存在一些缺陷,或未經測試的角落,從而留下了一些安全漏洞。
所以,只要可能,可以使用經過廣泛測試並得到驗證的安全代碼。而且框架也提供了特性完備的授權過濾器,並能夠擴展實現自定義授權策略。
一個更安全的辦法是創建一個AuthorizeAttribute類的子類,讓它照管所有棘手的事情,而且編寫自定義的授權代碼是很容易的。這裡為了演示這種方式的實現,在示例項目中添加了一個Infrastructure文件夾,在這個文件夾中我創建了一個新的類文件:CustomAuthAttribute.cs,其內容如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Infrastructure { public class CustomAuthAttribute : AuthorizeAttribute { private bool _localAllowed; public CustomAuthAttribute(bool allowedParam) { this._localAllowed = allowedParam; } protected override bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext.Request.IsLocal) { return this._localAllowed; } else { return true; } } } }
這是一個簡單的授權過濾器,它實現了阻止本地請求的訪問(所謂本地請求就是一種瀏覽器與應用程式伺服器在同一設備上運行而形成的請求,如開發用機)。
在這個示例中繼承了AuthorizeAttribute類,並重寫了AuthorizeCore方法。這樣即實現了自定義授權的目的,也保證了能夠獲益AuthorizeAttribute的其他內建特性。在構造函數中,使用了一個布爾值,用以指示是否允許本地請求。
這裡重寫的這個AuthorizeCore方法,是MVC框架用以檢查過濾器,是否隊請求進行授權訪問的方式。其接收的參數是HttpContexBase對象,通過該參數可以獲得待處理請求的信息。通過利用AuthorizeAttribute基類的內建特性,只需要關註授權邏輯,併在想要對請求進行授權時,從AuthorizeCore方法中返回true,而再不想授權時返回false。
保持授權註解屬性簡單
以上對AuthorizeCore方法傳遞了一個HttpContextBase對象,該對象所提供的是對請求信息進行訪問的方法,而不是訪問運用該註解屬性的控制器和方法的信息。開發人員直接實現IAuthorizationFilter介面的主要原因,是為了獲得對傳遞給OnAuthorization方法的AuthorizationContext的訪問,通過它可以得到更廣範的信息,包括路由細節,以及當前控制器和動作方法的信息。
一般是不建議自行實現IAuthorizationFilter介面的,主要是因為不僅編寫自己的安全代碼是不危險的。雖然授權是一種交叉關註,但會在授權註解屬性中建立一些邏輯,這些邏輯會與控制器緊密地耦合在一起,這會破壞關註分離,並導致測試和維護的問題。要儘可能保持授權註解屬性簡單,並關註基於請求的授權——讓授權的上下文來自於運用該註解屬性的地方。
運用自定義授權過濾器
可以像預設的過濾器那樣使用自定義的授權過濾器,如下演示的這樣(加粗部分):
using Filters.Infrastructure; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Controllers { public class HomeController : Controller { /// <summary> /// 一個返回字元串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字元串值發送給瀏覽器 /// (這隻是為了簡化,在實際的項目中還是應該使用視圖——這裡只關註控制器) /// </summary> /// <returns></returns> [CustomAuth(false)] public string Index() { return "This is the Index action on the Home Controller"; } } }
示例中將過濾器構造函數的參數設置為false,表示本地請求將被拒絕訪問Index動作方法。如果運行程式,併在本機瀏覽器進行訪問,則將看到授權被拒絕的結果,如圖:
本地請求被自定義授權過濾器拒絕訪問
使用內建的授權過濾器
內建的授權過濾器:AuthorizeAttribute擁有自己的實現,它將通過AuthorizeCore方法實現常規的授權任務。
當直接使用AuthorizeAttribute時,可以用這個類的兩個公共屬性來指定授權策略,下表給出了這兩個屬性的簡單介紹:
名稱 |
類型 |
描述 |
Users |
string |
一個逗號分割的用戶名稱列表,允許這些用戶訪問該動作方法 |
Roles |
string |
一個逗號分割的角色列表。為了訪問該動作方法,用戶必須至少是這就角色之一。 |
下麵是這兩個屬性的使用示例(加粗):
using Filters.Infrastructure; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Controllers { public class HomeController : Controller { /// <summary> /// 一個返回字元串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字元串值發送給瀏覽器 /// (這隻是為了簡化,在實際的項目中還是應該使用視圖——這裡只關註控制器) /// </summary> /// <returns></returns> //[CustomAuth(false)] [Authorize(Users = "adam,steve,jacqui", Roles = "admin")] public string Index() { return "This is the Index action on the Home Controller"; } } }
上述示例中同時指定了用戶和角色,這表示除非兩個條件都滿足,否則將不授予許可權。這裡還有一個隱含條件,即該請求已被認證。如果未指定任何用戶或角色,那麼任何已被認證的用戶都可以使用這個動作方法。
提示:AuthorizeAttribute處理授權,但不負責認證。但我們可以使用任何ASP.NET內建的認證系統或開發自己的認證系統(建議最好使用內建認證系統)。只要認證系統使用標準的ASP.NET的API,那麼,AuthorizeAttribute就能限制對控制器和動作的訪問。
對於大多數情況,AuthorizeAttribute提供的授權策略已經足夠了。但如果希望實現一些特殊功能,可以通過這個類進行派生。雖然這樣比直接實現IAuthorizationFilter介面的風險要小很多,但在開發的過程中還要非常謹慎的考慮策略的影響,並對它進行充分的測試。
使用異常過濾器
只有在調用一個動作方法時,如果拋出未處理的異常,異常過濾器才會運行。這種異常的來源主要有以下幾種:
- 另一個過濾器(授權、動作或結構過濾器);
- 動作方法本身;
- 當動作結果被執行時。
創建異常過濾器
異常過濾器必須實現IExceptionFilter介面,該介面的命名空間為:System.Web.Mvc,其中OnException方法是在發送異常時被調用的。該方法的參數是一個繼承自ControllerContext的ExceptionContext類型的對象,它提供了很多有用的屬性可以用來獲取關於請求的信息,如下表:
名稱 |
類型 |
描述 |
Controller |
ControllerBase |
返回請求的控制器對象 |
HttpContext |
HttpContextBase |
提供對請求細節的訪問,以及對響應的訪問 |
IsChildAction |
bool |
若是子動作,便返回true |
RequestContext |
RequestContext |
提供對HttpContext和路由數據的訪問,通過其他屬性,兩者都是可用的 |
RouteData |
RouteData |
返回請求的路由數據 |
上表中的屬性都是繼承自ControllerContext的,除此之外,它還定義了一些附加屬性,見下表:
名稱 |
類型 |
描述 |
ActionDescriptior |
ActionDescriptior |
提供動作方法的細節 |
Result |
ActionResult |
用於動作方法的結果:通過將該屬性設置為一個非空值過濾器可以取消這個請求 |
Exception |
Exception |
未處理異常 |
ExceptionHandled |
bool |
如果另一個過濾器已經把這個異常標記為“已處理”,則返回true |
被拋出的異常可以通過Exception屬性進行操作。將ExceptionHandled屬性設置為“true”,異常過濾器可以報告它已經處理了該異常。但即便如此,應用於一個動作的所有異常過濾器還是會被調用,所以,一個比較好的處理方式是檢測另一個過濾器是否已經處理了這個問題,以免恢復另一個過濾器已經解決了的問題。
註:如果一個動作方法的所有異常過濾器均為將ExceptionHandled屬性設置為“true”,MVC框架將使用預設的ASP.NET異常處理器。這將會顯示恐怖的“黃色屏幕”。
Result屬性由異常過濾器使用,已告訴MVC框架要做什麼。異常過濾器的兩個主要用途是對異常進行日誌,並將適當的消息顯示給用戶。下麵我們通過 類來演示該如何使用:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Infrastructure { public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter { public void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled && filterContext.Exception is ArgumentOutOfRangeException) { filterContext.Result = new RedirectResult("~/Content/RangerErrorPage.html"); filterContext.ExceptionHandled = true; } } } }
這裡對ArgumentOutOfRangeException實例進行了處理,採取的辦法是將用戶瀏覽器重定向到Content文件夾中名為RangerErrorPage.html文件。
需要註意該類繼承了FilterAttribute類,此外還實現了IExceptionFilter介面。為了讓一個.NET註解屬性類被視為一個MVC過濾器,該類必須實現IMvcFilter介面。我們可以直接實現該介面,但最簡單的方式是通過FilterAttribute來派生自己的類,它已經實現了所以需要的介面,並提供一些有用的基本特性,如處理過濾器執行的預設處理順序。
運用異常過濾器
在使用異常過濾器之前還需要前面提到的Content文件夾和RangerErrorPage.html文件(靜態的HTML文件)。在本示例中將使用該文件顯示一些簡單的消息。代碼如下:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Rang Error</title> </head> <body> <h2>Sorry</h2> <span>One of the arguments was out of the expected range.</span> </body> </html>
下麵,需要對Home控制器添加一個動作方法,它將拋出我們感興趣的異常。添加的內容如下:
… public string RangeTest(int id) { if (id > 100) { return string.Format("The id value is:{0}", id); } else { throw new ArgumentOutOfRangeException("id", id, ""); } } …
啟動程式,並導航至/Home/RangeTest/50(如我的完整URL是:http://localhost:4081/Home/RangeTest/50),便可以看到預設的異常處理結果。(Visual Studio為MVC項目創建的預設路由中,具有一個名為id的片段變數,針對這一URL,它的值將被設為50,這回得到下圖的響應結果)。
可以將異常過濾器運用於控制器或個別動作,如:
… [RangeException] public string RangeTest(int id) { if (id > 100) { return string.Format("The id value is:{0}", id); } else { throw new ArgumentOutOfRangeException("id", id, ""); } } …
在此導航至/Home/RangeTest/50,將得到如下結果:
使用視圖來響應異常
通過顯示靜態內容的頁面來處理異常是簡單且安全的,但這對用戶來說沒有什麼用處。——最多也就能得到一個泛泛的警告,最後選擇退出程式。最好的辦法是使用視圖來顯示問題的細節,併為其提供一些上下文信息和選項,以幫助用戶對異常採取處理。
對於該示例,這裡做出了一些調整,將RangeExceptionAttribute類修改成如下這樣(加粗部分和註釋部分為修改內容):
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Infrastructure { public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter { public void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled && filterContext.Exception is ArgumentOutOfRangeException) { int val = (int)(((ArgumentOutOfRangeException)filterContext.Exception).ActualValue); filterContext.Result = new ViewResult { ViewName = "RangeError", ViewData = new ViewDataDictionary<int>(val) }; // 下麵註釋掉的方式顯示了一個靜態頁面內容 //filterContext.Result = new RedirectResult("~/Content/RangerErrorPage.html"); filterContext.ExceptionHandled = true; } } } }
這裡創建了一個ViewResult對象,並設置了ViewName和ViewData屬性的值,以指定視圖名稱和要傳遞給視圖的模型對象。這樣寫顯得代碼有些凌亂是直接使用ViewResult對象,而不是在Controller類定義的動作方法中使用View方法的原因。這裡我們沒必要關註這些,只要明白如何實現這一效果即可。後面我們會通過內建的異常過濾器更好的實現同樣效果。
這裡我們指定了一個名為RangeError的視圖,並傳了一個int型的參數值,以這個引起異常的參數值作為視圖模型對象。後面,繼續在項目中添加一個Views/Shared文件夾,並創建RangeError.cshtml文件:
@model int <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Range Error</title> </head> <body> <h2>The value @Model was out of the expected range.</h2> <div> @Html.ActionLink("Change value and try again", "Index") </div> </body> </html>
由於示例功能有限,未向用戶指示出解決這一問題的任何有用信息,但這裡使用ActionLink輔助器方法創建了一個指向另一個動作方法的連接,目的是演示可以使用一整套視圖特性。再次啟動程式,並導航至/Home/RangeTest/50,將看到如下效果:
避免異常錯誤陷阱
使用視圖來顯示錯誤消息的好處是可以使用佈局是錯誤消息與應用程式的其餘部分一致,並生成動態的內容,幫助用戶瞭解發生了什麼錯誤,以及提示他們可以如何處理問題。
但是這麼做也存在一些缺陷:這就要求我們在開發的過程當中必須徹底的測試視圖,以確保不會產生其他異常。作為簡單示例,這裡對RangeError.cshtml視圖添加了一個Razor代碼塊,很明顯它將拋出一個異常,如:
@model int @{ // 用來演示在異常視圖信息中拋出異常的情況 var count = 0; var number = Model / count; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Range Error</title> </head> <body> <h2>The value @Model was out of the expected range.</h2> <div> @Html.ActionLink("Change value and try again", "Index") </div> </body> </html>
當該視圖被渲染時,將會生成一個DivideByZeroException(被零除異常)。如果啟動程式,並導航至/Home/RangeTest/50,將會看到拋出的異常,該異常是在視圖渲染期間拋出的,且不由控制器拋出。如下圖:
這個演示雖不是真是場景,但它說明瞭當視圖有問題時發送的情況——用戶看到了一個困惑的錯誤提示,甚至與他們在程式中遇到的問題毫不相關。所以,在使用一個依賴於視圖的異常過濾器時,必須小心謹慎地對視圖進行充分的測試。
使用內建的異常過濾器
在實際的項目中一般不需要向前面將的那樣去創建自己的過濾器,MVC框架包含了HandleErrorAttribute異常過濾器,它是內建IExceptionFilter介面的實現。該異常過濾器有一些常用的屬性,可以用來指定一個異常以及視圖和佈局名稱,詳見下表:
名稱 |
類型 |
描述 |
ExceptionType |
Type |
由過濾器處理的異常類型。它也處理通過給定值繼承而來的異常類型,但會忽略所有其他類型。其預設值是System.Exception,其含義為,預設地處理所有標準異常 |
View |
string |
該過濾器渲染的視圖模板名。如果未指定一個值,則採用預設的Error值,因此,預設情況下會渲染/Views/<currentCotrollerName>/Error.cshtml或/Views/Shared/Error.cshtml |
Master |
string |
在渲染這過濾器的視圖時所使用的佈局名稱。如果未指定一個值,該視圖使用其預設佈局頁面 |
當遇到由ExceptionType指定類型的未處理異常時,此過濾器將渲染由View屬性指定的視圖(使用預設佈局,或有Master屬性指定的佈局)。
1.使用內建異常過濾器要做的準備
只有在Web.config文件中啟用了自定義錯誤時,HandleErrorAttribute過濾器才會生效,這可以在<system.web>節點中添加一個customErrors屬性即可,如:
… <system.web> <httpRuntime targetFramework="4.5" /> <compilation debug="true" targetFramework="4.5" /> <pages> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages" /> </namespaces> </pages> <customErrors mode="On" defaultRedirect="/Content/RangeErrorPage.html"/> </system.web> …
model屬性的預設值是RemoteOnly,意為在開發期間,HandleErrorAttribute將不會攔截異常,但將應用程式部署到產品伺服器,並從另一臺電腦發出請求時才會生效。為了看到用戶最終將看到的情況,要確保已經將這個自定義錯誤模式設置為“On”。defaultRedirect屬性指定了一個內容頁面,在其他情況下都無法顯示異常消息時,便會使用該頁面。
2.運營內建的異常過濾器
下麵我們看看該如何使用這一內建的異常過濾器:
… [HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "RangeError")] public string RangeTest(int id) { if (id > 100) { return string.Format("The id value is:{0}", id); } else { throw new ArgumentOutOfRangeException("id", id, ""); } } …
該示例重建了前面自定義過濾器一樣的情況,即通過將視圖顯示給用戶的方式來處理ArgumentOutOfRangeException異常。
在渲染視圖時,HandleErrorAttribute過濾器會傳遞一個HandleErrorInfo視圖模型對象,這是一個封裝了異常細節的封裝程式,它提供了可在視圖中使用的附加信息,下表給出了HandleErrorInfo類定義的屬性:
名稱 |
類型 |
描述 |
ActionName |
string |
返回生成異常的動作方法名稱 |
ControllerName |
string |
返回生成異常的控制器名稱 |
Exception |
Exception |
返回此異常 |
下麵將演示如何使用這個模型對象來更新RangeError.cshtml視圖:
<!--使用 HandleErrorInfo 模型對象--> @model HandleErrorInfo <!--model int--> @{ //// 用來演示在異常視圖信息中拋出異常的情況 //var count = 0; //var number = Model / count; // 使用 HandleErrorInfo 模型對象 ViewBag.Title = "Sorry,there was a problem!"; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Range Error</title> </head> <body> @*<h2>The value @Model was out of the expected range.</h2> <div> @Html.ActionLink("Change value and try again", "Index") </div>*@ <!--使用 HandleErrorInfo 模型對象--> <h2>Sorry</h2> <span> The value @(((ArgumentOutOfRangeException)Model.Exception).ActualValue) was out of the expected range. </span> <div> @Html.ActionLink("Change value and try again", "Index") </div> <!--放在 div 中且將 display 設為 none 可將堆棧的跟蹤情況隱藏--> <div style="display:none"> <!--必須包含該屬性的值,否則將不能顯示異常視圖--> @Model.Exception.StackTrace </div> </body> </html>
該視圖中必須將Model.Exception屬性值轉為ArgumentOutOfRangeException類型,以便能夠讀取ActualValue屬性,因為HandleErrorInfo類是一個用來將任何異常傳遞給視圖的一個通用的模型對象。
註意:在使用HandleError過濾器時有一個奇怪的行為,即視圖中必須包含Model. Exception. StackTrace屬性的值,否則視圖便不會顯示給用戶。但因為不想顯示堆棧的跟蹤情況,所以將該值的輸出放在一個div元素中,並將其CSS的display屬性設置為none,使之對用戶是不可見的。
其效果和使用前述自定義異常過濾器一樣,如圖:
使用動作過濾器
動作過濾器是可以被用於任何目的的多用途過濾器。創建這種過濾器需要實現介面IActionFilter,在MSDN中給出的描述是這樣的:
命名空間:System.Web.Mvc
語法:public interface IActionFilter
公開成員(方法):