ASP.NET MVC集成EntLib实现“自动化”异常处理[实现篇]
通过《 实例篇 》的实演示可以看出我们通过扩展实现的自动异常处理机制能够利用EntLib的EHAB根据执行的一场处理策略对某个Action方法执行过程中抛出的异常进行处理。对于处理后的结果,则按照如下的机制对请求进行响应。[源代码从 这里 下载][本文已经同步到《 How ASP.NET MVC Works? 》中]
对于Ajax请求,直接创建一个用于封装被处理后异常的数据对象,并据此创建一个JsonResult将异常信息回复给客户端。 对于非Ajax请求,如果当前Action方法上应用HandleErrorActionAttribute特性设置了匹配的Action方法用于处理该方法抛出的异常,那么执行该方法并用返回的ActionResult对象响应当前请求。 如果HandleErrorActionAttribute特性不曾应用在当前Action方法上,或者通过该特性指定的Action不存在,则将默认的错误View呈现出来作为多请求的响应。目录
一、ExceptionPolicyAttribute & HandleErrorActionAttribute
一、ExceptionPolicyAttribute & HandleErrorActionAttribute
二、实现在OnException方法中的异常处理逻辑
三、将处理后的错误消息存放在HttpContext的Items中
四、用于设置错误消息的ErrorMessageHandler所有的这些都是通过一个自定义的ExceptionFilter来实现的。不过我们并没有定义任何的ExceptionFilter特性,而是将异常处理实现在一个自定义的ExtendedController基类中,对异常的自动处理实现在重写的OnException方法中,不过在介绍该方法的逻辑之前我们先来看看定义在ExtendedController中的其他辅助成员。
1: public class ExtendedController: Controller2: {3: private static Dictionary<Type, ControllerDescriptor> controllerDescriptors = new Dictionary<Type, ControllerDescriptor>();4: private static object syncHelper = new object ();5:6: protected override void OnException(ExceptionContext filterContext)7: {8: //省略成员9: }10:11: //描述当前Controller的ControllerDescriptor12: public ControllerDescriptor Descriptor13: {14: get15: {16: ControllerDescriptor descriptor;17: if (controllerDescriptors.TryGetValue( this .GetType(), out descriptor))18: {19: return descriptor;20: }21: lock (syncHelper)22: {23: if (controllerDescriptors.TryGetValue( this .GetType(), out descriptor))24: {25: return descriptor;26: }27: else28: {29: descriptor = new ReflectedControllerDescriptor( this .GetType());30: controllerDescriptors.Add( this .GetType(), descriptor);31: return descriptor;32: }33: }34: }35: }36: //获取异常处理策略名称37: public string GetExceptionPolicyName()38: {39: string actionName = ControllerContext.RouteData.GetRequiredString( "action" );40: ActionDescriptor actionDescriptor = this .Descriptor.FindAction(ControllerContext, actionName);41: if ( null == actionDescriptor)42: {43: return string .Empty;44: }45: ExceptionPolicyAttribute exceptionPolicyAttribute = actionDescriptor.GetCustomAttributes( true ).OfType<ExceptionPolicyAttribute>().FirstOrDefault()??46: Descriptor.GetCustomAttributes( true ).OfType<ExceptionPolicyAttribute>().FirstOrDefault()?? new ExceptionPolicyAttribute( "" );47: return exceptionPolicyAttribute.ExceptionPolicyName;48: }49:50: //获取Handle-Error-Action名称51: public string GetHandleErrorActionName()52: {53: string actionName = ControllerContext.RouteData.GetRequiredString( "action" );54: ActionDescriptor actionDescriptor = this .Descriptor.FindAction(ControllerContext, actionName);55: if ( null == actionDescriptor)56: {57: return string .Empty;58: }59: HandleErrorActionAttribute handleErrorActionAttribute = actionDescriptor.GetCustomAttributes( true ).OfType<HandleErrorActionAttribute>().FirstOrDefault()??60: Descriptor.GetCustomAttributes( true ).OfType<HandleErrorActionAttribute>().FirstOrDefault()?? new HandleErrorActionAttribute( "" );61: return handleErrorActionAttribute.HandleErrorAction;62: }63:64: //用于执行Handle-Error-Action的ActionInvoker65: public HandleErrorActionInvoker HandleErrorActionInvoker { get; private set; }66:67: public ExtendedController()68: {69: this .HandleErrorActionInvoker = new HandleErrorActionInvoker();70: }71: }ExtendedController的Descriptor属性用于返回描述自身的ControllerDescriptor对象,实际上是一个ReflectedControllerDescriptor对象。为了避免频繁的反射操作造成对性能的影响,我们将基于某个类型解析出来的ReflectedControllerDescriptor对象进行了全局性缓存。
GetExceptionPolicyName方法用于返回当前采用的异常处理策略名称。异常处理策略名称是通过具有如下定义的ExceptionPolicyAttribute特性来指定的。该特性既可以应用在Controller类型上,也可以应用在Action方法上,换句话说,我们可以采用不同的策略来处理从不同Action执行过程中抛出的异常。GetExceptionPolicyName利用ControllerDesctior和ActionDescriptor可以很容易地得到应用的ExceptionPolicyAttribute特性,进而得到相应的异常处理策略名称。
1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Method, AllowMultiple = false , Inherited = true )]2: public class ExceptionPolicyAttribute: Attribute3: {4: public string ExceptionPolicyName { get; private set; }5: public ExceptionPolicyAttribute( string exceptionPolicyName)6: {7: this .ExceptionPolicyName = exceptionPolicyName;8: }9: }另一个方法GetHandleErrorActionName用于获取通过应用在Action方法上的特性HandleErrorActionAttribute设置的Handle-Error-Action的名称。该特性定义如下,它既可以应用于某个Action方法,也可以应用于Controller类。GetHandleErrorActionName方法同样利用ControllerDesctior和ActionDescriptor得到应用的ExceptionPolicyAttribute特性,并最终得到对应的异常处理Action名称。
1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Method, AllowMultiple = false )]2: public class HandleErrorActionAttribute: Attribute3: {4: public string HandleErrorAction { get; private set; }5: public HandleErrorActionAttribute( string handleErrorAction = "" )6: {7: this .HandleErrorAction = handleErrorAction;8: }9: }通过HandleErrorActionAttribute特性设置的Handle-Error-Action需要手工执行以实现对当前请求的响应,为此我们创建了一个具有如下定义的HandleErrorActionInvoker。它是ControllerActionInvoker的子类,Handle-Error-Action需要手工执行以实现对当前请求的响应的执行通过虚方法InvokeActionMethod来完成。ExtendedController的HandleErrorActionInvoker返回的就是这样一个对象。
1: public class HandleErrorActionInvoker: ControllerActionInvoker2: {3: public virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor)4: {5: IDictionary< string , object > parameterValues = this .GetParameterValues(controllerContext, actionDescriptor);6: return base .InvokeActionMethod(controllerContext, actionDescriptor, parameterValues);7: }8: }
二、实现在OnException方法中的异常处理逻辑整个异常处理和最终对请求的相应实现在如下所示的OnException方法中,流程并不复杂,在这里就不一一赘述了。不过对于整个处理流程,有两个点值得一提:其一,在调用EntLib的EHAB对异常处理过程中,允许相应的ExceptionHandler设置一个友好的错误消息,而这个消息被保存在当前HttpContext的Items中。其二,在调用异常处理方法之前,我们错误消息添加到当前的ModelState中,这也是为什么在上面的实例演示中错误消息会自动出现在ValidationSummary中的根本原因。
1: public class ExtendedController: Controller2: {3: //其他成员4: protected override void OnException(ExceptionContext filterContext)5: {6: //或者当前的ExceptionPolicy,如果不存在,则直接调用基类OnException方法7: string exceptionPolicyName = this .GetExceptionPolicyName();8: if ( string .IsNullOrEmpty(exceptionPolicyName))9: {10: base .OnException(filterContext);11: return ;12: }13:14: //利用EntLib的EHAB进行异常处理,并获取错误消息和最后抛出的异常15: filterContext.ExceptionHandled = true ;16: Exception exceptionToThrow;17: string errorMessage;18: try19: {20: ExceptionPolicy.HandleException(filterContext.Exception,exceptionPolicyName, out exceptionToThrow);21: errorMessage = System.Web.HttpContext.Current.GetErrorMessage();22: }23: finally24: {25: System.Web.HttpContext.Current.ClearErrorMessage();26: }27: exceptionToThrow = exceptionToThrow ?? filterContext.Exception;28:29: //对于Ajax请求,直接返回一个用于封装异常的JsonResult30: if (Request.IsAjaxRequest())31: {32: filterContext.Result = Json( new ExceptionDetail(exceptionToThrow, errorMessage));33: return ;34: }35:36: //如果设置了匹配的HandleErrorAction,则调用之;37: //否则将Error View呈现出来38: string handleErrorAction = this .GetHandleErrorActionName();39: string controllerName = ControllerContext.RouteData.GetRequiredString( "controller" );40: string actionName = ControllerContext.RouteData.GetRequiredString( "action" );41: errorMessage = string .IsNullOrEmpty(errorMessage) ? exceptionToThrow.Message : errorMessage;42: if ( string .IsNullOrEmpty(handleErrorAction))43: {44: filterContext.Result = View( "Error" , new ExtendedHandleErrorInfo(exceptionToThrow, controllerName, actionName, errorMessage));45: }46: else47: {48: ActionDescriptor actionDescriptor = Descriptor.FindAction(ControllerContext, handleErrorAction);49: ModelState.AddModelError( "" , errorMessage);50: filterContext.Result = this .HandleErrorActionInvoker.InvokeActionMethod(ControllerContext, actionDescriptor);51: }52: }53: }
三、将处理后的错误消息存放在HttpContext的Items中在调用EntLib的EHAB进行异常处理之后从当前HttpContext提取错误消息,以及最后清除消息分别是通过HttpContext的扩展方法GetErrorMessage和ClearErrorMessage实现的。如下面的代码片断所示,除了这两个扩展方法我们还定义了另一个用于设置错误消息的SetErrorMessage方法。
1: public static class HttpContextExtensions2: {3: public static string keyOfErrorMessage = Guid.NewGuid().ToString();4:5: public static void SetErrorMessage( this HttpContext context, string errorMessage)6: {7: context.Items[keyOfErrorMessage]=errorMessage;8: }9:10: public static string GetErrorMessage( this HttpContext context)11: {12: return context.Items[keyOfErrorMessage] as string ;13: }14:15: public static void ClearErrorMessage( this HttpContext context)16: {17: if (context.Items.Contains(keyOfErrorMessage))18: {19: context.Items.Remove(keyOfErrorMessage);20: }21: }22: }
四、用于设置错误消息的ErrorMessageHandler用于设置错误信息的ErrorMessageHandler以及对应配置元素类型ErrorMessageHandlerData定义如下。ErrorMessageHandler表示错误消息的ErrorMessage属性在构造函数中被初始化,而在实现的HandleException方法中直接通过调用当前HttpContext的扩展方法SetErrorMessage进行错误消息的设置。
1: [ConfigurationElementType( typeof (ErrorMessageHandlerData))]2: public class ErrorMessageHandler: IExceptionHandler3: {4: public string ErrorMessage { get; private set; }5: public ErrorMessageHandler( string errorMessage)6: {7: this .ErrorMessage = errorMessage;8: }9: public Exception HandleException(Exception exception, Guid handlingInstanceId)10: {11: if ( null != HttpContext.Current)12: {13: HttpContext.Current.SetErrorMessage( this .ErrorMessage);14: }15: return exception;16: }17: }18:19: public class ErrorMessageHandlerData : ExceptionHandlerData20: {21: [ConfigurationProperty( "errorMessage" , IsRequired= true )]22: public string ErrorMessage23: {24: get { return ( string ) this [ "errorMessage" ]; }25: set { this [ "errorMessage" ] = value ; }26: }27:28: public override IEnumerable<TypeRegistration> GetRegistrations( string namePrefix)29: {30: yield return new TypeRegistration<IExceptionHandler>(() => new ErrorMessageHandler( this .ErrorMessage))31: {32: Name = this .BuildName(namePrefix),33: Lifetime = TypeRegistrationLifetime.Transient34: };35: }36: }ASP.NET MVC集成EntLib实现“自动化”异常处理[实例篇]
ASP.NET MVC集成EntLib实现“自动化”异常处理[实现篇]作者: Artech
出处: http://artech.cnblogs测试数据/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
分类: [02] 编程技巧 , [14] 框架设计
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于ASP.NET MVC集成EntLib实现“自动化”异常处理[实现篇]的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did48297