五、自定义Controller:BaseController
ExceptionActionInvoker最终在我们自定义的Controller基类BaseController中被调用的。ExceptionActionInvoker对象在构造函数中被初始化,并在重写的OnException方法中被调用。
- usingSystem;
- usingSystem.Web.Mvc;
- namespaceArtech.Mvc.ExceptionHandling
- {
- publicabstractclassBaseController : Controller
- {
- publicBaseController(stringexceptionPolicy)
- {
- Func<string, HandleErrorInfo, ViewResult> getErrorView = (viewName, handleErrorInfo) => this.View(viewName, handleErrorInfo);
- this.ExceptionActionInvoker = newExceptionActionInvoker(exceptionPolicy,getErrorView);
- }
- publicBaseController(ExceptionActionInvoker actionInvoker)
- {
- this.ExceptionActionInvoker = actionInvoker;
- }
- publicvirtualExceptionActionInvoker ExceptionActionInvoker { get; privateset; }
- protectedvirtualstringGetHandleErrorActionName(stringactionName)
- {
- returnstring.Format("On{0}Error", actionName);
- }
- protectedoverridevoidOnException(ExceptionContext filterContext)
- {
- using(ExceptionHandlingContextScope contextScope = newExceptionHandlingContextScope(filterContext))
- {
- stringactionName = RouteData.GetRequiredString("action");
- stringhandleErrorActionName = this.GetHandleErrorActionName(actionName);
- this.ExceptionActionInvoker.InvokeAction(filterContext, handleErrorActionName);
- foreach(var error inExceptionHandlingContext.Current.Errors)
- {
- ModelState.AddModelError(Guid.NewGuid().ToString() ,error.ErrorMessage);
- }
- }
- }
- }
- }
|
值得一提的是:整个OnException方法中的操作都在一个ExceptionHandlingContextScope中进行的。顾名思义, 我们通过ExceptionHandlingContextScope为ExceptionHandlingContext创建了一个范围。ExceptionHandlingContext定义如下,我们可以通过它获得当前的ExceptionContext和ModelErrorCollection,而静态属性Current返回当前的ExceptionHandlingContext对象。
- publicclassExceptionHandlingContext
- {
- [ThreadStatic]
- privatestaticExceptionHandlingContext current;
- publicExceptionContext ExceptionContext { get; privateset; }
- publicModelErrorCollection Errors { get; privateset; }
- publicExceptionHandlingContext(ExceptionContext exceptionContext)
- {
- this.ExceptionContext = exceptionContext;
- this.Errors = newModelErrorCollection();
- }
- publicstaticExceptionHandlingContext Current
- {
- get { returncurrent; }
- set { current = value;}
- }
- }
|
在BaseController的OnException方法中,当执行了ExceptionActionInvoker的InvokeAction之后,我们会将当前ExceptionHandlingContext的ModelError转移到当前的ModelState中。这就是为什么我们会通过ValidationSummary显示错误信息的原因。对于我们的例子来说,错误消息的指定是通过如下所示的ErrorMessageSettingHandler 实现的,而它仅仅将指定的错误消息添加到当前ExceptionHandlingContext的Errors属性集合中而已。
- [ConfigurationElementType(typeof(ErrorMessageSettingHandlerData))]
- publicclassErrorMessageSettingHandler : IExceptionHandler
- {
- publicstringErrorMessage { get; privateset; }
- publicErrorMessageSettingHandler(stringerrorMessage)
- {
- this.ErrorMessage = errorMessage;
- }
- publicException HandleException(Exception exception, Guid handlingInstanceId)
- {
- if(null== ExceptionHandlingContext.Current)
- {
- thrownewInvalidOperationException("...");
- }
- if(string.IsNullOrEmpty(this.ErrorMessage))
- {
- ExceptionHandlingContext.Current.Errors.Add(exception.Message);
- }
- else
- {
- ExceptionHandlingContext.Current.Errors.Add(this.ErrorMessage);
- }
- returnexception;
- }
- }
|