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; } }
【相干引荐】
1.ASP免费视频教程
2.ASP教程
3.李炎恢ASP基本视频教程
以上就是ASP.NET下关于EntLib的非常处置惩罚的处置惩罚方案的细致内容,更多请关注ki4网别的相干文章!