在MVC2.0 中 遭遇无法被 Try Catch 的 “Exception”

  前天当我为新项目新增完日志模块后对日志模块进行测试,测试时居然发现开发人员一段非常简单的代码,而且很标准的try ... catch .. 写法。代码整理如下:

public JsonResult SaveTest()

{

try

{

//LinqToSql:返回IQueryable数据集合。

var iQueryableData = (from o in _Context.Orders//.Where(o => o.OrderID == 10248)

select new

{

ShipName = o.ShipName,

Employee = o.Employee,

}).ToList();

//LINQ:返回IEnumerable集合。

var iEnumerableData = from d in iQueryableData

select new

{

ShipName = d.ShipName,

EmployeeName = d.Employee.LastName //空引用未处理引发程序异常。

};

return Json(new { Success = true, Msg = iEnumerableData }, JsonRequestBehavior.AllowGet);

}

catch (Exception ex)

{

return Json(new { Success = false, Msg = ex.Message }, JsonRequestBehavior.AllowGet);

}

}

  为方便大家阅读,我用 NORTHWIND 数据库。同时在该数据库内执行 SQL :update orders set EmployeeID =null where OrderID =10248 。这样造成上述代码第18 行Linq代码迭代时产生异常。您认为 这个异常可以被catch住么?答案当然是否定的!

当发现这个Bug后顿时让我产生了兴趣,我不知道如果微软的MVC项目开发人员看到这个bug,他是如何解释的。接下来让我就来一个非官方解释吧,欢迎拍砖!

我们可以在第18行设置好断点,然后用VS2010 Debug程序,发现执行到第 21 行 return Json 时 VS未报任何bug。过数秒后断点直接定位在第18行,提示也很简单:未将对象应用到实例。这个确实是我们预期想要的 Exception 但是它始终没有被 catch 住!通过StackTrace我发现了这么一句提示: at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) 。上述代码第21行return Json 被执行后返回了 JsonAction 这个 JsonAction 被 InvokeActionResult 调用?难道这个就是问题的关键所在?原因是写有try catch 函数(本例的SaveTest()函数)的外层调用函数(InvokeActionResult()函数)出现了异常。也就是外层函数出现异常我们的内层函数SaveTest()又怎能try catch 到这个外层异常呢?于是通过Reflector进一步证实我的想法。具体的请看下图:

  主要是这句action.ExecuteResult(ControllerContext);它的执行过程如下:

  最后一幅图的JavaScriptSerializer serializer = new JavaScriptSerializer(); 进行 json 序列化时这个外层函数报出了异常。这个异常在我们的内层函数 SaveTest() 方法内是不可能被截获到的。此刻我已完全弄明白这个无法被catch 的exception 是怎么出现的!至于这个异常为什么会被外层函数触发,主要是.net Linq 延迟加载机制导致的,这不属于本文讨论的范畴,具体的园子内很多文章已经解释的很清楚了。

为消灭掉这个截获不到的exception现附上解决方案:

MVC虽然很年轻,但是这个架构真的很优秀我们可以非常方便对其扩展(我不是MVC的托,呵呵)。为了解决问题,我们只要自定义一个特性该特性继承 HandleErrorAttribute  特性即可。接着重写基类的 OnException 虚方法。代码如下:

public class CustomHandleErrorAttribute : HandleErrorAttribute

{

public override void OnException(ExceptionContext Context)

{

base.OnException(Context);

dynamic ex = Context.Exception;

if (!Context.ExceptionHandled)

return;

//TODO:将 ex 错误对象记录到
系统日志模块

}

}

  接着我们在MVC Controller 内这样调用:

/*

*截获InvokeActionResult 调用 actionResult参数的 ExecuteResult 方法。

ExecuteResult 方法执行时 进行 以下操作:

JavaScriptSerializer serializer = new JavaScriptSerializer();

response.Write(serializer.Serialize(this.Data));

将C# 匿名对象序列化成json数据供 jquery ajax 方法回调。

*/

[CustomHandleError]

public JsonResult SaveTest()

{

//try

//{

//TestMehod();

//LinqToSql:返回IQueryable数据集合。

var iQueryableData = (from o in _Context.Orders//.Where(o => o.OrderID == 10248)

select new

{

ShipName = o.ShipName,

Employee = o.Employee,

}).ToList();

//LINQ:返回IEnumerable集合。

var iEnumerableData = from d in iQueryableData

select new

{

ShipName = d.ShipName,

EmployeeName = d.Employee.LastName //空引用未处理引发不可截获的异常。

};

return Json(new { Success = true, Msg = iEnumerableData }, JsonRequestBehavior.AllowGet); //Json序列化。

//}

//catch //外层错误,导致内层函数catch失效,无法有效的截取错误信息。

//{

// return Json(new { Success = false, Msg = "操作失败。" }, JsonRequestBehavior.AllowGet);

//}

}

  代码看上去更简洁了吧?连try catch 都不用写了更不用担心啥时候这个截获不到的exception神秘人物登场,这样噩梦结束了。

  本例代码这里下载

时间: 2024-10-11 18:14:59

在MVC2.0 中 遭遇无法被 Try Catch 的 “Exception”的相关文章

一起谈.NET技术,在MVC2.0 中 遭遇无法被 Try Catch 的 “Exception”

前天当我为新项目新增完日志模块后对日志模块进行测试,测试时居然发现开发人员一段非常简单的代码,而且很标准的try ... catch .. 写法.代码整理如下: public JsonResult SaveTest(){try {//LinqToSql:返回IQueryable数据集合. var iQueryableData = (from o in _Context.Orders//.Where(o => o.OrderID == 10248) select new { ShipName =

使用VS2010和MVC2.0增强验证功能

在开始之前,我不得不说明我已经安装了VS 2010 RC1,并使用它将老版本转换为ASP.Net 4.0 大多数情况下,当你接收到来自用户从form表单post来的信息后,你的验证代码往往会检查相应的值是否存在,数据类型是否正确以及数据的范围是否正确.至少,你应该保证每当一个函数接受用户输入时,就应该执行相应的验证逻辑.这意味着有些时候在整个程序中的不同位置,你会对同一个或者相似的值进行多次验证.比如说你想限制用户的姓氏不大于20个字符,那这样的验证需要在程序的好几个部分实现.直到Jan Ven

走进ASP.NET MVC 3.0中的Razor模板引擎

随着MVC3.0RTM版本的发布,最近将公司的项目从MVC2.0升级到MVC3.0.同时打算在MVC3中全面使用Razor模板引擎.现将Razor学习拿出来和大家分享,如果存在不足的地方欢迎您指出. 其实在使用<%= %>在html中调用C#代码时,内心总在埋怨.这个写法非常麻烦.麻烦在哪呢?其实就是闭合.比如: Asp.net: <script src="<%=Url.Content("~/Scripts/jquery-1.4.4.min.js")%

MVC2.0 用Area 扩展项目的目录结构

Area是MVC2.0里新特性,但是感觉在项目中应用的不是很多,也许是项目比较小吧,没有在意目录结构的整理,举个例子来说吧,比如我们在管理自己项目的后台时候需要建立一个Admin目录,总感觉Admin建在View目录下不是很好,而且对URL显示也不是很完美..比如/Admin/index.aspx- 如果能有一个目录来单独管理Admin 是很完美滴- 在 MVC1.0时没办法实现这个功能,MVC2.0 提供了Area 特性,用来管理越来越庞大的项目目录结构.. 在VS2010里面项目上右键.添加

MVC2.0:用Area扩展项目的目录结构

Area是MVC2.0里新特性,但是感觉在项目中应用的不是很多,也许是项目比较小吧,没有在意目录结构的 整理,举个例子来说吧,比如我们在管理自己项目的后台时候需要建立一个Admin目录,总感觉Admin建在 View目录下不是很好,而且对URL显示也不是很完美..比如/Admin/index.aspx- 如果能有一个目录来单独 管理Admin 是很完美滴- 在 MVC1.0时没办法实现这个功能,MVC2.0 提供了Area 特性,用来管理越来越庞大的项目目录结 构.. 在VS2010里面项目上右

Asp.net MVC2.0系列文章-显示列表和详细页面操作

上一篇文章,我们简单地完成了新闻的添加操作(Asp.net MVC2.0系列文章-添 加操作)此篇文章,我们使用Asp.net MVC2.0实现新闻清单的展示和新闻详细页面 . 创建View视图Index和NewsDetails 创建新闻首页,用来显示新闻列表. 在Views/News目录下,单击右键,选择Add->View,修改相关配置如下图所 示 在生成的HTML代码中,进行相关展示方面的修改.主要代码如下: <% foreach (var item in Model) { %> &

在MVC2.0使用Lodop为WEB打印提出完美解决方案

通过好友CallHot介绍Lodopweb打印控件.由于是国人开发的,故这两天认真了研究下,打算在未来的项目中使用.现将学习成果与园友分享.如果存在不足的地方,希望您指出. 具体的实现步骤如下: 一.准备工作 1.MVC2.0 + jQuery1.4.1 开发环境. 2.Lodop web 打印控件,官方地址:http://mtsoftware.v053.gokao.net/download.html  (注:国人开发,免费软件). 3.StringTemplate,C#开源模板引擎.官方地址:

腾讯野心在微信 5.0中的显现

    微信 5.0的发布,从2月5日到8月5日,整整六个月,足足刷新了一款热门应用的更新周期. 微信 5.0 作为一个"大"版本,但是新版本却迟至今天才发布,其中内外部权益梳理.产品打磨.腾讯中长期规划都是影响因素.六个月的时间里,马化腾定性微信为"腾讯国际化的机会",并对微信提出商业化的要求,前者我们确实能从微信疯涨的海外用户看出,而后者我们在今天的微信 5.0 中终于看到了框架. 大家都知道,刚刚发布的微信5.0,加入调整了多项功能,其实都围绕着一个中心点--

在MVC2.0使用Lo“.NET研究”dop为WEB打印提出完美解决方案

通过好友CallHot介绍Lodopweb打印控件.由于是国人开发的,故这两天认真了研究下,打算在未来的项目中使用.现将学习成果与园友分享.如果存在不足的地方,希望您指出. 具体的实现步骤如下: 一.准备工作   1.MVC2.0 + jQuery1.4.1 开发环境. 2.Lodop web 打印控件,官方地上海闵行企业网站设计与制作址:http://mtsoftware.v053.gokao.net/download.html  (注:国人开发,免费软件). 3.StringTemplate