加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

ASP.NET MVC集成EntLib实现“自动化”异常处理[实例篇]

发布时间:2020-12-16 09:08:51 所属栏目:asp.Net 来源:网络整理
导读:个人觉得异常处理对于程序员来说是最为熟悉的同时也是最难掌握的。说它熟悉,因为仅仅就是try/catch/finally而已。说它难以掌握,则是因为很多开发人员却说不清楚try/catch/finally应该置于何处?什么情况下需要对异常进行日志记录?什么情况下需要对异常进

个人觉得异常处理对于程序员来说是最为熟悉的同时也是最难掌握的。说它熟悉,因为仅仅就是try/catch/finally而已。说它难以掌握,则是因为很多开发人员却说不清楚try/catch/finally应该置于何处?什么情况下需要对异常进行日志记录?什么情况下需要对异常进行封装?什么情况下需要对异常进行替换?对于捕获的异常,在什么情况下需要将其再次抛出?什么情况下则不需要?

合理的异常处理应该是场景驱动的,在不同的场景下,采用的异常处理策略往往是不同的。异常处理的策略应该是可配置的,因为应用程序出现怎样的异常往往是不可预测的,现有异常策略的不足往往需要在真正出现某种异常的时候才会体现出来,所以我们需要一种动态可配置的异常处理策略维护方式。目前有一些开源的异常处理框架提供了这种可配置的、场景驱动的异常处理方式,EntLib的Exception Handling Application Block(以下简称EHAB)就是一个不错的选择。[源代码从这里下载][本文已经同步到《How ASP.NET MVC Works?》中]

目录
一、通过指定Handle-Error-Action响应请求
二、通过Error View显示错误消息
三、自动创建JsonResult响应Ajax请求

一、通过指定Handle-Error-Action响应请求

在正式介绍如何通过扩展实现与EntLib以实现自动化异常处理之前,我们不妨先来体验一下异常处理具有怎样的“自动化”特性。以用户登录场景为例,我们在通过Visual Studio的ASP.NET MVC项目模板创建的Web应用中定义了如下一个简单的数据类型LoginInfo封装用户登录需要输入的用户名和密码。

   1: public class LoginInfo
   3:     [DisplayName("用户名")]
   5:     string UserName { get; set; }
   7:     [DisplayName("密码")]
  10:     string Password { get; set; }
    
   2: class HomeController : ExtendedController
   4:     public ActionResult Index()
   6:         return View(new LoginInfo());
   8:? 
  10:     [HandleErrorAction("OnIndexError")]
  12:     {
  14:         {
  16:         }
  18:         if (loginInfo.Password != "password")
  20:             new InvalidPasswordException();
  22:         return View(loginInfo);
  24:? 
  26:     public ActionResult OnIndexError(LoginInfo loginInfo)
  28:           29:     }
   1: @model LoginInfo
   3:     head>
   7:         style   8:        9:     body  10:         @using (Html.BeginForm())
  12:             @Html.ValidationSummary(true)
  14:             input ="submit" value="登录" />
  16:       17: >

通过HomeController的定义我们知道两种不同类型的异常(InvalidUserNameException和InvalidPasswordException)分别在输入无效用户名和密码是被抛出来,而我们需要处理的就是这两种类型的异常。正对它们的异常处理策略定义在如下的配置中,策略名称就是通过应用在HomeController上的ExceptionPolicyAttribute特性指定的“defaultPolicy”。

4: ="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings,Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" 5: 6: exceptionHandling 7: exceptionPolicies 8: add ="defaultPolicy" 9: exceptionTypes 10: ="MvcApp.InvalidUserNameException,MvcApp" postHandlingAction="ThrowNewException" ="InvalidUserNameException" 11: exceptionHandlers 12: name ="ErrorMessageHandler" ="MvcApp.ErrorMessageHandler,1)">errorMessage="用户名不存在" 13: 14: add 15:?
  26: >

通过上面的这样异常策略配置可以看到:我们使用一个自定义的名为ErrorMessageHandler的ExceptionHandler来处理抛出来的InvalidUserNameException和InvalidPasswordException异常,而ErrorMessageHandler仅仅是指定一个友好的错误消息,该消息一般会呈现给最终的用户。运行该程序后一个用于登录页面会呈现出来,当我们输入错误的用户名和密码的时候,相应的错误消息(在配置中通过ErrorMessageHandler设置的错误消息)会以如图7-16所示的效果显示出来,其实整个View是通过执行Action方法OnIndexError返回的ViewResult呈现出来的。

二、通过Error View显示错误消息

除了通过执行对应的Handle-Error-Action来呈现异常处理后的最终结果之外,还支持错误页面的错误呈现方法。简单起见,我们只是用名称为Error的View来作为最终的错误页面。为了演示基于错误页面的呈现方式,我们按照如下的方式重新定义了ViewsShared目录下的Error.cshtml。

2: @{
   4: }
  12:       13:   14:   15:     h3  16:         @Html.DisplayFor(m=>m.ErrorMessage)
  22:               23:                 >Message: @Html.DisplayFor(m => m.Exception.Message)  24:                 >Type: @Model.Exception.GetType().FullName  25:                 >StackTrace: @Html.DisplayFor(m => m.Exception.StackTrace)  26:               27:           28:       29:   30: >

上面这个View的Model类型是具有如下定义的ExtendedHandleErrorInfo。它继承自HandleErrorInfo,只额外定义了一个表示错误消息的ErrorMessage属性。在上面的这个View中,我们将错误消息、异常类型和StackTrace和当前Controller/Action的名称呈现出来。

string ErrorMessage { get; private set; }
   5:         : base(exception,controllerName,actionName)
this.ErrorMessage = errorMessage;
   9: }

当利用EntLib的EHAB对从Index方法中抛出的异常进行处理后采用错误View的方式来响应请求,我们需要按照如下的方式将应用在该方法上的HandleErrorActionAttribute特性注释掉。

//其他成员
   6:     //[HandleErrorAction("OnIndexError")]
//省略实现
  11: }

再次运行该程序并分别输入错误的用户名和密码后,默认的错误View(Error.cshtml)将会以如下图所示地效果把处理后的异常结果呈现出来。

三、自动创建JsonResult响应Ajax请求

用于实施认证的Action方法Index可以通过普通的HTTP-POST的形式来调用,同样也可以通过Ajax请求的方式来调用。对于Ajax请求来说,我们最终会将通过EntLib处理后的异常封装成如下一个类型为ExceptionDetail的对象。如下面的代码片断所示,ExceptionDetail具有与Exception对应的属性设置。最终根据抛出异常对象创建的ExceptionDetail对象会被用于创建一个JsonResult对象对当前Ajax请求予以响应。

public ExceptionDetail(Exception exception,1)">string errorMessage=null)
this.HelpLink = exception.HelpLink;
this.StackTrace = exception.StackTrace;
if (exception.InnerException !=   10:         {
  12:         }
  14:? 
public ExceptionDetail InnerException { get; set; }
string StackTrace { get; set; }
  20: }

当客户端接收到回复的Json对象后,可以通过检测其是否具有一个ExceptionType属性(对于一个ExceptionDetail对象来说,该属性不可能为Null)来判断是否发生异常。作为演示我们对Action方法Index对应的View进行了如下的改动。