EntLib的异常处理应用块(Exception Handling Application Block)是一个不错的异常处理框架,它使我们可以采用配置的方式来定义异常处理策略。而ASP.NET MVC是一个极具可扩展开发框架,在这篇文章中我将通过它的扩展实现与EntLib的集成,并提供一个完整的解决异常处理解决方案。
一、基本异常处理策略
我们首先来讨论我们的解决方案具体采用的异常处理策略:
对于执行Controller的某个Action方法抛出的异常,我们会按照指定配置策略进行处理。我们可以采取日志记录、异常替换和封装这些常用的异常处理方式;
对于处理后的异常,如果异常处理策略规定需要将其抛出,则会自动重定向到与异常类型匹配的出错页面。我们会维护一个异常类型和Error View的匹配关系;
对于处理后的异常,如果异常处理策略规定不需要将其抛出,则会执行与当前Action操作相匹配的错误处理Action进行处理。异常处理Action方法默认采用“On{Action}Error”这样的命名规则,而当前上下文会与异常处理操作方法的参数进行绑定。除次之外,我们会设置当前ModelState的错误信息;
如果用户不曾定义相应的异常处理Action,依然采用“错误页面重定向”方式进行异常处理。
二、通过自定义Action处理异常
为了让读者对上面介绍的异常处理页面有一个深刻的理解,我们来进行一个实例演示。该实例用于模拟用户登录,我们定义了如下一个只包含用户名和密码两个属性的Model:LoginInfoModel。
namespace Artech.Mvc.ExceptionHandling.Models
{
public class LoginInfo
{
[Display(Name ="User Name")]
[Required(ErrorMessage = "User Name is manadatory!")]
public string UserName { get; set; }
[Display(Name = "Password")]
[DataType(DataType.Password)]
[Required(ErrorMessage = "Password is manadatory!")]
public string Password { get; set; }
}
}
</div>
我们定义了如下一个AccountController,它是我们自定义的BaseController的子类。AccountController在构造的时候调用基类构造函数指定的参数代表异常处理策略的配置名称。SignIn方法代表用于进行“登录”的操作,而OnSignInError就表示该操作对应的异常处理操作。如果在SignIn操作中抛出的异常经过处理后无需再抛出,则会通过调用OnSignInError,而此时ModelState已经被设置了相应的错误消息。
public class AccountController BaseController
{
public AccountController()
base("myPolicy")
{ }
public ActionResult SignIn()
{
return View(new LoginInfo());
}
[HttpPost]
public ActionResult SignIn(LoginInfo loginInfo)
{
if (!ModelState.IsValid)
{
return this.View(new LoginInfo { UserName = loginInfo.UserName });
}
if (loginInfo.UserName != "Foo")
{
throw new InvalidUserNameException();
}
if (loginInfo.Password != "password")
{
throw new UserNamePasswordNotMatchException();
}
ViewBag.Message = "Authentication Succeeds!";
return this.View(new LoginInfo { UserName = loginInfo.UserName });
}
public ActionResult OnSignInError(string userName)
{
return this.View(new LoginInfo { UserName = userName });
}
}
</div>
具体定义在SignIn操作方法中的认证逻辑是这样的:如果用户名不是“Foo”则抛出InvalidUserNameException异常;如果密码不是“password”则抛出UserNamePasswordNotMatchException异常。下面是SignIn操作对应的View的定义:
@model Artech.Mvc.ExceptionHandling.Models.LoginInfo
@{
ViewBag.Title = "SignIn";
}
@Html.ValidationSummary()
@if (ViewBag.Messages != null)
{
@ViewBag.Messages
}
@using (Html.BeginForm())
{
@Html.EditorForModel()
<input type="submit" value="SignIn" />
}
</div>
在AccountController初始化时指定的异常处理策略“myPolicy”定义在如下的配置中。我们专门针对SignIn操作方法抛出的InvalidUserNameException和UserNamePasswordNotMatchException进行了处理,而ErrorMessageSettingHandler是我们自定义的异常处理器,它仅仅用于设置错误消息。如下面的代码片断所示,如果上述的这两种类型的异常被抛出,最终的错误消息会被指定为“User name does not exist!”和“User name does not match password!”。
<exceptionHandling>
<exceptionPolicies>
<add name="myPolicy">
<exceptionTypes>
<add name="InvalidUserNameException"
type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling"
postHandlingAction="None">
<exceptionHandlers>
<add name="ErrorMessageSettingHandler"
type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling"
errorMessage="User name does not exist!"/>
</exceptionHandlers>
</add>
<add name="UserNamePasswordNotMatchException"
type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling"
postHandlingAction="None">
<exceptionHandlers>
<add name="ErrorMessageSettingHandler"
type="Artech.Mvc.ExceptionHandling.ErrorMessageSettingHandler, Artech.Mvc.ExceptionHandling"
errorMessage="User name does not match password!"/>
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
</exceptionHandling>
</div>
现在我们通过路由映射将AccountController和Sign设置为默认Controller和Action后,开启我们的应用程序。在输入错误的用户名和错误明码的情况下在ValidationSummary中将自动得到相应的错误消息。

三、通过配置的Error View处理异常
在上面的配置中,针对InvalidUserNameException和UserNamePasswordNotMatchException这两种异常类型的配置策略都将PostHandlingAction属性设置为“None”,意味着不会将原来的异常和处理后的异常进行重新抛出。现在我们将该属性设置为“ThrowNewException”,意味着我们会将处理后的异常重新抛出来。
<exceptionHandling>
<exceptionPolicies>
<add name="myPolicy">
<exceptionTypes>
<add name="InvalidUserNameException" type="Artech.Mvc.ExceptionHandling.Models.InvalidUserNameException, Artech.Mvc.ExceptionHandling"
postHandlingAction="ThrowNewException">
...
<add name="UserNamePasswordNotMatchException" type="Artech.Mvc.ExceptionHandling.Models.UserNamePasswordNotMatchException, Artech.Mvc.ExceptionHandling"
postHandlingAction="ThrowNewException">
...
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
</exceptionHandling>
</div>
按照我们上面的异常处理策略,在这种情况下我们将采用“错误页面”的方式来进行异常处理。也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>
</div>
如上面的配置所示,我们为InvalidUserNameException和UserNamePasswordNotMatchException这两种异常类型定义了不同的Er
您可能想查找下面的文章:
- 详解ASP.NET MVC 常用扩展点:过滤器、模型绑定
- ASP.NET MVC从视图传参到控制器的几种形式
- ASP.NET MVC 4 中的JSON数据交互的方法
- ASP.NET MVC制作404跳转实例(非302和200)
- 详解ASP.NET MVC 利用Razor引擎生成静态页
- 详解ASP.NET MVC 解析模板生成静态页(RazorEngine)
- ASP.NET MVC4 利用uploadify.js多文件上传
- ASP.NET mvc4中的过滤器的使用
- Asp.net MVC下使用Bundle合并、压缩js与css文件详解
- 详解Asp.Net MVC——控制器与动作(Controller And Action)

