【发布时间】:2015-01-20 04:03:09
【问题描述】:
我现在已经两次看到从生产 ASP.NET MVC 4 Web 应用程序记录的NullReferenceException - 并且登录到错误的行。一两行没有错(就像 PDB 不匹配一样),但整个控制器操作的长度是错误的。示例:
public ActionResult Index()
{
var someObject = GetObjectFromService();
if (someObject.SomeProperty == "X") { // NullReferenceException here if someObject == null
// do something
}
// about 40 more lines of code
return View(); // Stack trace shows NullReferenceException here
}
对于同一控制器上的操作,这种情况已经发生了两次。第二种情况已登录
// someObject is known non-null because of earlier dereferences
return someObject.OtherProperty
? RedirecToAction("ViewName", "ControllerName")
: RedirectToAction("OtherView", "OtherController");
这很令人不安。 NullReferenceException 一旦知道它出现在哪一行,就很容易修复。如果异常可能发生在控制器动作中的任何地方,那就不太容易了!
有没有人在 ASP.NET MVC 或其他地方见过类似的东西?我愿意相信这是 Release 构建和 Debug 构建之间的区别,但仍然相差 40 行?
编辑:
明确一点:我是“What is a NullReferenceException and how do I fix it?”的原作者。我知道NullReferenceException 是什么。这个问题是关于为什么堆栈跟踪会如此远离。我见过由于 PDB 不匹配而导致堆栈跟踪关闭一两行的情况。我见过没有 PDB 的情况,所以你没有得到行号。但我从未见过堆栈跟踪偏离 32 行的情况。
编辑 2:
请注意,这发生在同一控制器中的两个单独的控制器操作中。他们的代码彼此完全不同。事实上,在第一种情况下,NullReferenceException 甚至没有出现在条件句中——它更像是这样的:
SomeMethod(someObject.SomeProperty);
在优化过程中,有可能代码已被重新组织,因此实际的NullReferenceException 更接近return,而 PDB 实际上只偏离了几行。但是我看不到重新排列方法调用的机会,这种方式会导致代码移动 32 行。其实我只是看了一下反编译的源码,好像没有重新整理过。
这两种情况的共同点是:
- 它们出现在同一个控制器中(到目前为止)
- 在这两种情况下,堆栈跟踪都指向
return语句,在这两种情况下,NullReferenceException都出现在距return语句 30 行或更多行的地方。
编辑 3:
我刚刚做了一个实验 - 我刚刚使用我们已部署到生产服务器的“生产”构建配置重新构建了解决方案。我在本地 IIS 上运行了解决方案,根本没有更改 IIS 配置。
堆栈跟踪显示正确的行号。
编辑 4:
我不知道这是否相关,但导致NullReferenceException 的情况与这个“错误的行号”问题本身一样不寻常。我们似乎无缘无故失去了会话状态(没有重新启动或任何事情)。这并不奇怪。奇怪的是,当发生这种情况时,我们的 Session_Start 应该重定向到登录页面。任何重现会话丢失的尝试都会导致重定向到登录页面。随后使用浏览器“返回”按钮或手动输入上一个 URL 直接返回登录页面,而无需点击相关控制器。
所以也许两个奇怪的问题真的是一个非常奇怪的问题。
编辑 5:
我能够获得 .PDB 文件,并使用dia2dump 查看它。我认为 PDB 有可能搞砸了,并且 only 有该方法的第 72 行。事实并非如此。所有行号都存在于 PDB 中。
编辑 6:
为了记录,这又发生了,在第三个控制器中。堆栈跟踪直接指向方法的返回语句。 这个返回语句就是return model;。我认为没有任何方法可以导致NullReferenceException。
事实上,我只是更仔细地查看了日志并发现了几个不是 NullReferenceException 的异常,它们仍然在return 语句处具有堆栈跟踪点。这两种情况都在控制器动作中调用的方法中,而不是直接在动作方法本身中。其中一个是明确抛出的InvalidOperationException,一个是简单的FormatException。
以下是一些我之前认为不相关的事实:
- global.asax 中的
Application_Error是导致记录这些异常的原因。它通过使用Server.GetLastError()来获取异常。 - 日志记录机制分别记录消息和堆栈跟踪(而不是记录
ex.ToString(),这本来是我的建议)。特别是,我一直在询问的堆栈跟踪来自ex.StackTrace。 -
FormatException在System.DateTime.Parse中引发,从System.Convert.ToDate调用,从我们的代码调用。指向我们代码的堆栈跟踪行是指向“return model;”的行。
【问题讨论】:
-
有时视图本身可能存在具有空引用的逻辑。示例模型属性或可能是模型本身。检查您的视图以确保其中没有失败的内容。
-
我赞同 Azhar 的评论。我的猜测是你的视图在你的模型上调用了一些空的东西。
-
有趣的是,为什么人们对“我应该在这里获得例外,而不是在那里获得例外”的问题投反对票...
-
@BrianDriscoll
View()不会在视图上调用Execute(),因此视图中的任何 NRE 都不会在控制器的方法中抛出。我倾向于认为示例代码已经减少到永远无法重现异常的程度。就目前而言,这个问题无法回答,因为它没有Minimal, Complete, and Verifiable example。 -
使用来自 msft 的调试诊断。这将允许您在发生访问冲突时获取用户转储。然后你可以加载到windbg,看看你得到了什么堆栈。苔丝的博客可能会有所帮助blogs.msdn.com/b/tess
标签: c# asp.net asp.net-mvc asp.net-mvc-4 nullreferenceexception