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

个人觉得异常处理对于程序员来说是最为熟悉的同时也是最难掌握的。说它熟悉,因为仅仅就是try/catch/finally而已。说它难以 掌握,则是因为很多开发人员却说不清楚try/catch/finally应该置于何处?什么情况下需要对异常进行日志记录?什么情况下需要对异常进行封 装?什么情况下需要对异常进行替换?对于捕获的异常,在什么情况下需要将其再次抛出?什么情况下则不需要?
合理的异常处理应该是场景驱动 的,在不同的场景下,采用的异常处理策略往往是不同的。异常处理的策略应该是可配置的,因为应用程序出现怎样的异常往往是不可预测的,现有异常策略的不足 往往需要在真正出现某种异常的时候才会体现出来,所以我们需要一种动态可配置的异常处理策略维护方式。目前有一些开源的异常处理框架提供了这种可配置的、 场景驱动的异常处理方式,EntLib的Exception Handling Application Block(以下简称EHAB)就是一个不错的选择。[源代码从这里下载]

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

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

双击代码全选

1

1:publicclass LoginInfo

 

双击代码全选

1

2: {

 

双击代码全选

1

3:     [DisplayName("用户名")]

 

双击代码全选

1

4:     [Required(ErrorMessage="请输入{0}")]

 

双击代码全选

1

5:publicstring UserName { get; set; }

 

双击代码全选

1

 

 

双击代码全选

1

7:     [DisplayName("密码")]

 

双击代码全选

1

8:     [Required(ErrorMessage = "请输入{0}")]

 

双击代码全选

1

9:     [DataType(DataType.Password)]

 

双击代码全选

1

10:publicstring Password { get; set; }

 

双击代码全选

1

11: }

 

然 后我们定义了如下一个HomeController。基于HTTP-GET的Action方法Index将会呈现一个用户登录View,该View使用创 建的LoginInfo对象作为其Model。真正的用户验证逻辑定义在另一个应用了HttpPostAttrubute特性的Index方法中:如果用 户名不为Foo,抛出InvalidUserNameException异常;如果密码不是“password”,则抛出 InvalidPasswordException异常。InvalidUserNameException和 InvalidPasswordException是我们自定义的两种异常类型。

双击代码全选

1

1: [ExceptionPolicy("defaultPolicy")]

 

双击代码全选

1

2:publicclass HomeController : ExtendedController

 

双击代码全选

1

3: {

 

双击代码全选

1

4:public ActionResult Index()

 

双击代码全选

1

5:     {

 

双击代码全选

1

6:return View(new LoginInfo());

 

双击代码全选

1

7:     }

 

双击代码全选

1

 

 

双击代码全选

1

9:     [HttpPost]

 

双击代码全选

1

10:     [HandleErrorAction("OnIndexError")]

 

双击代码全选

1

11:public ActionResult Index(LoginInfo loginInfo)

 

双击代码全选

1

12:     {

 

双击代码全选

1

13:if (string.Compare(loginInfo.UserName, "foo", true) != 0)

 

双击代码全选

1

14:         {

 

双击代码全选

1

15:thrownew InvalidUserNameException();

 

双击代码全选

1

16:         }

 

双击代码全选

1

17:

 

双击代码全选

1

18:if (loginInfo.Password != "password")

 

双击代码全选

1

19:         {

 

双击代码全选

1

20:thrownew InvalidPasswordException();

 

双击代码全选

1

21:         }

 

双击代码全选

1

22:return View(loginInfo);

 

双击代码全选

1

23:     }

 

双击代码全选

1

24:

 

双击代码全选

1

25:     [HttpPost]

 

双击代码全选

1

26:public ActionResult OnIndexError(LoginInfo loginInfo)

 

双击代码全选

1

27:     {

 

双击代码全选

1

28:return View(loginInfo);

 

双击代码全选

1

29:     }

 

双击代码全选

1

30: }

 

上面定义的HomeController具有三点与自动化异常处理相关的地方:

  • HomeController继承自自定义的基类ExtendedController,后者完成了对异常的自动化处理。
  • HomeController类型上应用了自定义的ExceptionPolicyAttribute特性用于指定默认采用的异常处理策略名称(“defaultPolicy”)。
  • 基 于HTTP-POST的Index方法上应用了HandleErrorActionAttribute特性用于指定一个Handle-Error- Action名称,当异常在目标Action执行过程中抛出并通过EHAB处理后,指定的Action会被执行以实现对请求的响应。对于我们的例子来说, 从Index方法抛出的异常被处理后会调用OnIndexError方法作为对当前请求的响应。

下面是代表登录页面 的View的定义,这是一个Model类型为LoginInfo的强类型View。在该View中,作为Model的LoginInfo对象以编辑默认呈 现在一个表单中,表单中提供了一个“登录”提交表单。除此之外,View中还具有个ValidationSummary。

双击代码全选

1

1: @model LoginInfo

 

双击代码全选

1

2:<html>

 

双击代码全选

1

3:<head>

 

双击代码全选

1

4:<title>用户登录</title>

 

双击代码全选

1

5:<styletype="text/css">

 

双击代码全选

1

6:             .validation-summary-errors{color:Red}

 

双击代码全选

1

7:</style>

 

双击代码全选

1

8:</head>

 

双击代码全选

1

9:<body>

 

双击代码全选

1

10:         @using (Html.BeginForm())

 

双击代码全选

1

11:         {

 

双击代码全选

1

12:             @Html.ValidationSummary(true)

 

双击代码全选

1

13:             @Html.EditorForModel()

 

双击代码全选

1

14:<inputtype="submit"value="登录"/>

 

双击代码全选

1

15:         }

 

双击代码全选

1

16:</body>

 

双击代码全选

1

17:</html>

 

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

双击代码全选

1

1:<configuration>

 

双击代码全选

1

2:<configSections>

 

双击代码全选

1

3:<sectionname="exceptionHandling"

 

双击代码全选

1

4:type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"/>

 

双击代码全选

1

5:</configSections>

 

双击代码全选

1

6:<exceptionHandling>

 

双击代码全选

1

7:<exceptionPolicies>

 

双击代码全选

1

8:<addname="defaultPolicy">

 

双击代码全选

1

9:<exceptionTypes>

 

双击代码全选

1

10:<addtype="MvcApp.InvalidUserNameException, MvcApp"postHandlingAction="ThrowNewException"name="InvalidUserNameException">

 

双击代码全选

1

11:<exceptionHandlers>

 

双击代码全选

1

12:<addname="ErrorMessageHandler"type="MvcApp.ErrorMessageHandler, MvcApp"errorMessage="用户名不存在"/>

 

双击代码全选

1

13:</exceptionHandlers>

 

双击代码全选

1

14:</add>

 

双击代码全选

1

15:

 

双击代码全选

1

16:<addtype="MvcApp.InvalidPasswordException, MvcApp"postHandlingAction="ThrowNewException"name="InvalidPasswordException">

 

双击代码全选

1

17:<exceptionHandlers>

 

双击代码全选

1

18:<addname="ErrorMessageHandler"type="MvcApp.ErrorMessageHandler, MvcApp"errorMessage="密码与用户名不匹配"/>

 

双击代码全选

1

19:</exceptionHandlers>

 

双击代码全选

1

20:</add>

 

双击代码全选

1

21:</exceptionTypes>

 

双击代码全选

1

22:</add>

 

双击代码全选

1

23:</exceptionPolicies>

 

双击代码全选

1

24:</exceptionHandling>

 

双击代码全选

1

25:   ...

 

双击代码全选

1

26:</configuration>