ASP.NET MVC對異常處理的解決方法總結
ASP.NET MVC是一個極具可擴展開發框架,在這篇文章中我將透過它的擴展實現與EntLib的集成,並提供一個完整的解決異常處理解決方案。
EntLib的異常處理應用程式區塊(Exception Handling Application Block)是一個不錯的例外處理框架,它使我們可以採用配置的方式來定義異常處理策略。而ASP.NET MVC是一個極具可擴展開發框架,在這篇文章中我將透過它的擴展實現與EntLib的集成,並提供一個完整的解決異常處理解決方案。
一、基本異常處理策略
#我們首先來討論我們的解決方案具體採用的例外處理策略:
對於執行Controller的某個Action方法拋出的例外,我們會依照指定設定策略來處理。我們可以採取日誌記錄、異常替換和封裝這些常用的異常處理方式;
對於處理後的異常,如果異常處理策略規定需要將其拋出,則會自動重定向到與異常類型符合的出錯頁面。我們會維護一個異常類型和Error View的匹配關係;
對於處理後的異常,如果異常處理策略規定不需要將其拋出,則會執行與當前Action操作相符的錯誤處理Action進行處理。異常處理Action方法預設採用「On{Action}Error」這樣的命名規則,而目前上下文會與異常處理操作方法的參數綁定。除此之外,我們會設定目前ModelState的錯誤訊息;
如果使用者不曾定義對應的異常處理Action,依然採用「錯誤頁面重定向」方式進行異常處理。
二、透過自訂Action處理例外
#為了讓讀者對上面介紹的例外處理頁面有一個深刻的理解,我們來進行一個實例演示。這個實例用於模擬使用者登錄,我們定義瞭如下一個只包含使用者名稱和密碼兩個屬性的Model:LoginInfoModel。
namespace Artech.Mvc.ExceptionHandling.Models { public class LoginInfo { [Display(Name ="User Name")] [Required(ErrorMessage = "User Name is manadatory!")] public string UserName { get; set; } [Display(Name = "Password")] [DataType(DataType.Password)] [Required(ErrorMessage = "Password is manadatory!")] public string Password { get; set; } } }
我們定義瞭如下一個AccountController,它是我們自訂的BaseController的子類別。 AccountController在建構的時候呼叫基底類別建構子指定的參數代表異常處理策略的配置名稱。 SignIn方法代表用於進行「登入」的操作,而OnSignInError就表示該操作對應的異常處理操作。如果在SignIn操作中拋出的異常經過處理後無需再拋出,則會透過呼叫OnSignInError,而此時ModelState已經被設定了相應的錯誤訊息。
public class AccountController BaseController { public AccountController() base("myPolicy") { } public ActionResult SignIn() { return View(new LoginInfo()); } [HttpPost] public ActionResult SignIn(LoginInfo loginInfo) { if (!ModelState.IsValid) { return this.View(new LoginInfo { UserName = loginInfo.UserName }); } if (loginInfo.UserName != "Foo") { throw new InvalidUserNameException(); } if (loginInfo.Password != "password") { throw new UserNamePasswordNotMatchException(); } ViewBag.Message = "Authentication Succeeds!"; return this.View(new LoginInfo { UserName = loginInfo.UserName }); } public ActionResult OnSignInError(string userName) { return this.View(new LoginInfo { UserName = userName }); } }
具體定義在SignIn操作方法中的認證邏輯是這樣的:如果使用者名稱不是「Foo」則拋出InvalidUserNameException異常;如果密碼不是「password」則拋出UserNamePasswordNotMatchException異常。以下是SignIn操作對應的View的定義:
@model Artech.Mvc.ExceptionHandling.Models.LoginInfo @{ ViewBag.Title = "SignIn"; } @Html.ValidationSummary() @if (ViewBag.Messages != null) { @ViewBag.Messages } @using (Html.BeginForm()) { @Html.EditorForModel() <input type="submit" value="SignIn" /> }
在AccountController初始化時指定的例外處理策略「myPolicy」定義在如下的配置中。我們專門針對SignIn操作方法拋出的InvalidUserNameException和UserNamePasswordNotMatchException進行了處理,而ErrorMessageSettingHandler是我們自訂的例外處理器,它只用於設定錯誤訊息。如下面的程式碼片斷所示,如果上述的這兩種類型的異常被拋出,最終的錯誤訊息會被指定為「User name does not exist!」和「User name does not match password!」。
<exceptionHandling> <exceptionPolicies> <add name="myPolicy"> <exceptionTypes> <add name="InvalidUserNameException" type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" postHandlingAction="None"> <exceptionHandlers> <add name="ErrorMessageSettingHandler" type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling" errorMessage="User name does not exist!"/> </exceptionHandlers> </add> <add name="UserNamePasswordNotMatchException" type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling" postHandlingAction="None"> <exceptionHandlers> <add name="ErrorMessageSettingHandler" type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling" errorMessage="User name does not match password!"/> </exceptionHandlers> </add> </exceptionTypes> </add> </exceptionPolicies> </exceptionHandling>
現在我們透過路由映射將AccountController和Sign設定為預設Controller和Action後,開啟我們的應用程式。在輸入錯誤的使用者名稱和錯誤明碼的情況下在ValidationSummary中將自動得到對應的錯誤訊息。
三、透過設定的Error View處理異常
在上面的設定中,針對InvalidUserNameException和UserNamePasswordNotMatchException這兩種異常類型的配置策略都將PostHandlingAction屬性設為“None”,意味著不會將原來的異常和處理後的異常進行重新拋出。現在我們將該屬性設為“ThrowNewException”,這意味著我們會將處理後的例外重新拋出。
<exceptionHandling> <exceptionPolicies> <add name="myPolicy"> <exceptionTypes> <add name="InvalidUserNameException" type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" postHandlingAction="ThrowNewException"> ... <add name="UserNamePasswordNotMatchException" type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling" postHandlingAction="ThrowNewException"> ... </add> </exceptionTypes> </add> </exceptionPolicies> </exceptionHandling>
按照我們上面的例外處理策略,在這種情況下我們將採用「錯誤頁面」的方式來進行異常處理。也HandleErrorAttribute的處理方式類似,我們支援異常類型和Error View之間的匹配關係,而這是透過類似於如下的配置來定義的。值得一提的是,這裡的異常類型是經過處理後重新拋出的異常。
<artech.exceptionHandling> <add exceptionType="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" errorView="InvalideUserNameError"/> <add exceptionType="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling" errorView="UserNamePasswordNotMatchError"/> </artech.exceptionHandling>
如上面的配置所示,我們為InvalidUserNameException和UserNamePasswordNotMatchException這兩種異常類型定義了不同的Error View,分別是“InvalideUserNameError”和“UserNamePasswordNotMatchError”,詳細定義如下圖所示:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <p style="colorRed; font-weightbold">Sorry,the user name you specify does not exist!</p> </body> </html> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <p style="colorRed; font-weightbold">Sorry, The password does not match the given user name!</p> </body> </html>
现在我们按照上面的方式运行我们的程序,在分别输入错误的用户名和密码的情况下会自动显现相应的错误页面。
四、自定义ActionInvoker:ExceptionActionInvoker
对于上述的两种不同的异常处理方式最终是通过自定义的ActionInvoker来实现的,我们将其命名为ExceptionActionInvoker。如下面的代码片断所式,ExceptionActionInvoker直接继承自ControllerActionInvoker。属性ExceptionPolicy是一个基于指定的异常策略名称创建的ExceptionPolicyImpl 对象,用于针对EntLib进行的异常处理。而属性GetErrorView是一个用于获得作为错误页面的ViewResult对象的委托。整个异常处理的核心定义在InvokeAction方法中,该方法中指定的handleErrorActionName参数代表的是“异常处理操作名称”,整个方法就是按照上述的异常处理策略实现的。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Artech.Mvc.ExceptionHandling.Configuration; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling; namespace Artech.Mvc.ExceptionHandling { public class ExceptionActionInvoker ControllerActionInvoker { protected ExceptionHandlingSettings ExceptionHandlingSettings{get; private set;} protected virtual Func<string, HandleErrorInfo, ViewResult> GetErrorView { get; private set; } public ExceptionPolicyImpl ExceptionPolicy { get; private set; } public ExceptionActionInvoker(string exceptionPolicy,Func<string, HandleErrorInfo, ViewResult> getErrorView) { this.ExceptionPolicy = EnterpriseLibraryContainer.Current.GetInstance<ExceptionPolicyImpl>(exceptionPolicy); this.GetErrorView = getErrorView; this.ExceptionHandlingSettings = ExceptionHandlingSettings.GetSection(); } public override bool InvokeAction(ControllerContext controllerContext, string handleErrorActionName) { ExceptionContext exceptionContext = controllerContext as ExceptionContext; if (null == exceptionContext) { throw new ArgumentException("The controllerContext must be ExceptionContext!", "controllerContext"); } try { exceptionContext.ExceptionHandled = true; if (this.ExceptionPolicy.HandleException(exceptionContext.Exception)) { HandleRethrownException(exceptionContext); } else { if (ExceptionHandlingContext.Current.Errors.Count == 0) { ExceptionHandlingContext.Current.Errors.Add(exceptionContext.Exception.Message); } ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(exceptionContext); ActionDescriptor handleErrorAction = FindAction(exceptionContext, controllerDescriptor, handleErrorActionName); if (null != handleErrorAction) { IDictionary<string, object> parameters = GetParameterValues(controllerContext, handleErrorAction); exceptionContext.Result = this.InvokeActionMethod(exceptionContext, handleErrorAction, parameters); } else { HandleRethrownException(exceptionContext); } } return true; } catch (Exception ex) { exceptionContext.Exception = ex; HandleRethrownException(exceptionContext); return true; } } protected virtual void HandleRethrownException(ExceptionContext exceptionContext) { string errorViewName = this.GetErrorViewName(exceptionContext.Exception.GetType()); string controllerName = (string)exceptionContext.RouteData.GetRequiredString("controller"); string action = (string)exceptionContext.RouteData.GetRequiredString("action"); HandleErrorInfo handleErrorInfo = new HandleErrorInfo(exceptionContext.Exception, controllerName, action); exceptionContext.Result = this.GetErrorView(errorViewName, handleErrorInfo); } protected string GetErrorViewName(Type exceptionType) { ExceptionErrorViewElement element = ExceptionHandlingSettings.ExceptionErrorViews .Cast<ExceptionErrorViewElement>().FirstOrDefault(el=>el.ExceptionType == exceptionType); if(null != element) { return element.ErrorView; } if(null== element && null != exceptionType.BaseType!= null) { return GetErrorViewName(exceptionType.BaseType); } else { return "Error"; } } } }
五、自定义Controller:BaseController
ExceptionActionInvoker最终在我们自定义的Controller基类BaseController中被调用的。ExceptionActionInvoker对象在构造函数中被初始化,并在重写的OnException方法中被调用。
using System; using System.Web.Mvc; namespace Artech.Mvc.ExceptionHandling { public abstract class BaseController Controller { public BaseController(string exceptionPolicy) { Func<string, HandleErrorInfo, ViewResult> getErrorView = (viewName, handleErrorInfo) => this.View(viewName, handleErrorInfo); this.ExceptionActionInvoker = new ExceptionActionInvoker(exceptionPolicy,getErrorView); } public BaseController(ExceptionActionInvoker actionInvoker) { this.ExceptionActionInvoker = actionInvoker; } public virtual ExceptionActionInvoker ExceptionActionInvoker { get; private set; } protected virtual string GetHandleErrorActionName(string actionName) { return string.Format("On{0}Error", actionName); } protected override void OnException(ExceptionContext filterContext) { using (ExceptionHandlingContextScope contextScope = new ExceptionHandlingContextScope(filterContext)) { string actionName = RouteData.GetRequiredString("action"); string handleErrorActionName = this.GetHandleErrorActionName(actionName); this.ExceptionActionInvoker.InvokeAction(filterContext, handleErrorActionName); foreach (var error in ExceptionHandlingContext.Current.Errors) { ModelState.AddModelError(Guid.NewGuid().ToString() ,error.ErrorMessage); } } } } }
值得一提的是:整个OnException方法中的操作都在一个ExceptionHandlingContextScope中进行的。顾名思义, 我们通过ExceptionHandlingContextScope为ExceptionHandlingContext创建了一个范围。ExceptionHandlingContext定义如下,我们可以通过它获得当前的ExceptionContext和ModelErrorCollection,而静态属性Current返回当前的ExceptionHandlingContext对象。
public class ExceptionHandlingContext { [ThreadStatic] private static ExceptionHandlingContext current; public ExceptionContext ExceptionContext { get; private set; } public ModelErrorCollection Errors { get; private set; } public ExceptionHandlingContext(ExceptionContext exceptionContext) { this.ExceptionContext = exceptionContext; this.Errors = new ModelErrorCollection(); } public static ExceptionHandlingContext Current { get { return current; } set { current = value; } } }
在BaseController的OnException方法中,当执行了ExceptionActionInvoker的InvokeAction之后,我们会将当前ExceptionHandlingContext的ModelError转移到当前的ModelState中。这就是为什么我们会通过ValidationSummary显示错误信息的原因。对于我们的例子来说,错误消息的指定是通过如下所示的ErrorMessageSettingHandler 实现的,而它仅仅将指定的错误消息添加到当前ExceptionHandlingContext的Errors属性集合中而已。
[ConfigurationElementType(typeof(ErrorMessageSettingHandlerData))] public class ErrorMessageSettingHandler IExceptionHandler { public string ErrorMessage { get; private set; } public ErrorMessageSettingHandler(string errorMessage) { thisErrorMessage = errorMessage; } public Exception HandleException(Exception exception, Guid handlingInstanceId) { if (null == ExceptionHandlingContextCurrent) { throw new InvalidOperationException(""); } if (stringIsNullOrEmpty(thisErrorMessage)) { ExceptionHandlingContextCurrentErrorsAdd(exceptionMessage); } else { ExceptionHandlingContextCurrentErrorsAdd(thisErrorMessage); } return exception; } }
以上是ASP.NET MVC對異常處理的解決方法總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

隨著智慧型手機技術的不斷發展,手機在我們日常生活中扮演著越來越重要的角色。而作為一款專注於遊戲效能的旗艦手機,黑鯊手機備受玩家青睞。然而,有時候我們也會面臨到黑鯊手機開不了機的情況,這時候我們就需要採取一些措施來解決這個問題。接下來,就讓我們來分享五招教你解決黑鯊手機開不了機的問題:第一招:檢查電池電量首先,確保你的黑鯊手機有足夠的電量。可能是因為手機電量耗盡

而後悔莫及、人們常常會因為一些原因不小心刪除某些聯絡人、微信作為一款廣泛使用的社群軟體。幫助用戶解決這個問題,本文將介紹如何透過簡單的方法找回被刪除的聯絡人。 1.了解微信聯絡人刪除機制這為我們找回被刪除的聯絡人提供了可能性、微信中的聯絡人刪除機制是將其從通訊錄中移除,但並未完全刪除。 2.使用微信內建「通訊錄恢復」功能微信提供了「通訊錄恢復」節省時間和精力,使用者可以透過此功能快速找回先前刪除的聯絡人,功能。 3.進入微信設定頁面點選右下角,開啟微信應用程式「我」再點選右上角設定圖示、進入設定頁面,,

隨著社群媒體的不斷發展,小紅書已經成為越來越多年輕人分享生活、發現美好事物的平台。許多用戶在發布圖片時遇到了自動儲存的問題,這讓他們感到十分困擾。那麼,如何解決這個問題呢?一、小紅書發布自動儲存圖片怎麼解決? 1.清除快取首先,我們可以嘗試清除小紅書的快取資料。步驟如下:(1)開啟小紅書,點選右下角的「我的」按鈕;(2)在個人中心頁面,找到「設定」並點選;(3)向下捲動,找到「清除快取」選項,點擊確認。清除快取後,重新進入小紅書,嘗試發布圖片看是否解決了自動儲存的問題。 2.更新小紅書版本確保你的小

七彩虹主機板在中國國內市場享有較高的知名度和市場佔有率,但是有些七彩虹主機板的用戶還不清楚怎麼進入bios進行設定呢?針對這一情況,小編專門為大家帶來了兩種進入七彩虹主機板bios的方法,快來試試吧!方法一:使用u盤啟動快捷鍵直接進入u盤裝系統七彩虹主機板一鍵啟動u盤的快捷鍵是ESC或F11,首先使用黑鯊裝機大師製作一個黑鯊U盤啟動盤,然後開啟電腦,當看到開機畫面的時候,連續按下鍵盤上的ESC或F11鍵以後將會進入到一個啟動項順序選擇的窗口,將遊標移到顯示“USB”的地方,然

番茄小說是一款非常熱門的小說閱讀軟體,我們在番茄小說中經常會有新的小說和漫畫可以去閱讀,每一本小說和漫畫都很有意思,很多小伙伴也想著要去寫小說來賺取賺取零用錢,在把自己想要寫的小說內容編輯成文字,那麼我們要怎麼樣在這裡面去寫小說呢?小伙伴們都不知道,那就讓我們一起到本站本站中花點時間來看寫小說的方法介紹。分享番茄小說寫小說方法教學 1、先在手機上打開番茄免費小說app,點擊個人中心——作家中心 2、跳到番茄作家助手頁面——點擊創建新書在小說的結

大家都知道,如果電腦無法載入驅動程序,該設備可能就無法正常工作或與電腦進行正確的互動。那在電腦上彈出無法在此裝置上載入驅動程式的提示框,我們要如何解決呢?下面小編就教大家兩招輕鬆解決問題。 無法在此裝置上載入驅動程式解決方法 1、開始功能表搜尋「核心隔離」。 2、將記憶體完整性關閉,上方提示「記憶體完整性已關閉。你的裝置可能易受攻擊。」點擊後方忽略即可,不會對使用有影響。 3.重啟機器之後即可解決問題。

手機遊戲成為了人們生活中不可或缺的一部分,隨著科技的發展。它以其可愛的龍蛋形象和有趣的孵化過程吸引了眾多玩家的關注,而其中一款備受矚目的遊戲就是手機版龍蛋。幫助玩家們在遊戲中更好地培養和成長自己的小龍,本文將向大家介紹手機版龍蛋的孵化方法。 1.選擇合適的龍蛋種類玩家需要仔細選擇自己喜歡並且適合自己的龍蛋種類,根據遊戲中提供的不同種類的龍蛋屬性和能力。 2.提升孵化機的等級玩家需要透過完成任務和收集道具來提升孵化機的等級,孵化機的等級決定了孵化速度和孵化成功率。 3.收集孵化所需的資源玩家需要在遊戲中

字體大小的設定成為了重要的個人化需求,隨著手機成為人們日常生活的重要工具。以滿足不同使用者的需求、本文將介紹如何透過簡單的操作,提升手機使用體驗,調整手機字體大小。為什麼需要調整手機字體大小-調整字體大小可以使文字更清晰易讀-適合不同年齡段用戶的閱讀需求-方便視力不佳的用戶使用手機系統自帶字體大小設置功能-如何進入系統設置界面-在在設定介面中找到並進入"顯示"選項-找到"字體大小"選項並進行調整第三方應用調整字體大小-下載並安裝支援字體大小調整的應用程式-開啟應用程式並進入相關設定介面-根據個人
