一起谈.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 = 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-01 02:11:08

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

在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

一起谈.NET技术,MVC2.0本地化(另类解决方案)<下>

本文是对MVC2.0本地化(另类解决方案)上这篇文章内介绍的MVC2.0本地化功能进行加强.细化的结尾篇.如果存在不足的地方,希望您指出. 如何对上篇文章进行加强以及细化呢?主要从以下三点开始. 1.根据用户浏览器自动语言判断,同时也可由用户自定义站点语言. 2.多语言加入,类似resource文件,可以有多个语言资源库. 3.全局本地化,可以本地化非页面内容,比如为台异步到前台的json数据本地化等. 主要步骤如下: 一.根据用户浏览器自动语言判断,同时也可由用户自定义站点语言 这个实现思路为

一起谈.NET技术,MVC2.0本地化(另类解决方案)<上>

前不久看见一篇文章:在asp.net中使用Response.Filter 过滤网站敏感字符的解决方案.于是我借题发挥用Response.Filter 为MVC2.0 进行多国语言本地化.如果存在不足的地方,希望您指出. 本文主要给出具体思路,希望能给读者带来一定的启发:日常开发中不是所有的方案要中规中矩用常用方法解决问题.比如本文的本地化就不用resource文件来处理. 具体步骤: 一.建立自定义的LocalizationHandler类 LocalizationHandler 继承Syste

一起谈.NET技术,4.0中的并行计算和多线程详解(二)

相关文章:4.0中的并行计算和多线程详解(一) 多线程部分 多线程在4.0中被简化了很多,仅仅只需要用到System.Threading.Tasks.::.Task类,下面就来详细介绍下Task类的使用. 一.简单使用 开启一个线程,执行循环方法,返回结果.开始线程为Start(),等待线程结束为Wait(). Code         /// <summary>         /// Task简单使用         /// </summary>         private

一起谈.NET技术,WF4.0中如何实现XAML工作流的动态加载

我接下来还是用一个例子讲解一下如何在WF 4中动态加载xaml工作流的做法吧. 1. 创建自定义的Activity using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Activities; namespace WorkflowConsoleApplication1{ public sealed class MyActivity : CodeActivity

一起谈.NET技术,从.NET中委托写法的演变谈开去(上):委托与匿名方法

在<关于最近面试的一点感想>一文中,Michael同学谈到他在面试时询问对方"delegate在.net framework1.1,2.0,3.5各可以怎么写"这个问题.于是乎,有朋友回复道"请问楼主,茴香豆的茴有几种写法","当代孔乙己",独乐,众乐.看了所有的评论,除了某些朋友认为"的确不该不知道这个问题"之外,似乎没有什么人在明确支持楼主. 不过我支持,为什么?因为我也提过出这样的问题. 这样,我们暂且不提应

一起谈.NET技术,从.NET中委托写法的演变谈开去(中):Lambda表达式及其优势

在上一篇文章中我们简单探讨了.NET 1.x和.NET 2.0中委托表现形式的变化,以及.NET 2.0中匿名方法的优势.目的及注意事项.那么现在我们来谈一下.NET 3.5(C# 3.0)中,委托的表现形式又演变成了什么样子,还有什么特点和作用. .NET 3.5中委托的写法(Lambda表达式) Lambda表达式在C#中的写法是"arg-list => expr-body","=>"符号左边为表达式的参数列表,右边则是表达式体(body).参数列表

吴佰元:浅谈GPS技术在国土资源中的应用

[硅谷网9月26日讯]原文载于<科技与生活>杂志2012年第14期,文章称,社会在不断的前进与发展,当代信息化的时代里,对于各项技术的发展来讲,都是具有十分良好的前景与较大的发展空间.所以这些新技术的出现,为社会为人们的生活带来很多的便利.因此,在当代我们要充分利用这些新技术.新产品的力量推动我国各项事业不断前进的步伐. 关键词GPS技术:http://www.aliyun.com/zixun/aggregation/30834.html">国土资源:应用 国土资源是国民经济中

一起谈.NET技术,Silverlight 4中把DataGrid数据导出Excel—附源码下载

Silverlight中常常用到DataGrid来展示密集数据. 而常见应用系统中我们需要把这些数据导入导出到固定Office套件中例如常用的Excel表格. 那么在Silverlight 中如何加以实现? 在参考大量资料后 提供参考思路如下: A:纯客户端导出处理.利用Silverlight 与Javascript 进行交互实现导出Excel. B:服务器端导出.获得DataGrid数据源. 传递给WCF Service到服务器端. 然后把传回数据通过Asp.net中通用处理导出Excel方法