现在我们通过路由映射将AccountController和Sign设置为默认Controller和Action后,开启我们的应用程序。在输入错误的用户名和错误明码的情况下在ValidationSummary中将自动得到相应的错误消息。
三、通过配置的Error View处理异常
在上面的配置中,针对InvalidUserNameException和UserNamePasswordNotMatchException这两种异常类型的配置策略都将PostHandlingAction属性设置为“None”,意味着不会将原来的异常和处理后的异常进行重新抛出。现在我们将该属性设置为“ThrowNewException”,意味着我们会将处理后的异常重新抛出来。
<exceptionHandling> <exceptionPolicies> <add> <exceptionTypes> <add type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling" postHandlingAction="ThrowNewException"> ... <add 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>Sorry,the user name you specify does not exist!</p> </body> </html> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <p>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