我们在asp.net MVC .NET 4.0中运行一个非常大的Web应用程序。最近我们完成了审计,性能团队表示有很多空引用异常。
所以我开始从转储和事件查看器中调查它。 我的理解如下:
我们在控制器中使用Asyn Tasks。我们依赖HttpContext.Current.Items哈希表来存储很多应用程序级别的值。
Task<Articles>.Factory.StartNew(() =>
{
System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context;
var service = new ArticlesService(page);
return service.GetArticles();
}).ContinueWith(t => SetResult(t, "articles"));
因此我们将上下文对象复制到从Task factory生成的新线程上。此context.Items在必要时在线程中再次使用。 比如说:
public class SomeClass
{
internal static int StreamID
{
get
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
只要并行请求的数量最佳,这就可以正常运行。我的问题如下:
1。当负载更多且并行请求太多时,我注意到HttpContext.Current.Items为空。我无法找出原因,这会导致所有空引用异常。
2。我们如何确保它不为空?任何解决方法如果存在?
注意:我在StackOverflow中阅读并且人们有像HttpContext.Current这样的问题是null - 但在我的情况下它不是null而且是空的。我正在阅读另一篇文章,其中作者说有时请求对象被终止并且它可能会导致问题,因为已经在对象上调用了dispose。我正在做一个Context对象的副本 - 它只是一个浅拷贝而不是深拷贝。
答案 0 :(得分:2)
您的问题是HttpContext的实例成员不是线程安全的:
此类型的任何公共静态(在Visual Basic中为Shared)成员都是 线程安全。任何实例成员都不能保证是线程 安全
当您按照自己的方式(多个线程)访问它时,您需要自己进行同步。
static object locker = new object();
get
{
lock (locker)
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
答案 1 :(得分:0)
也许我误解了这一点,但我得到的印象是你只是试图阻止空引用错误。
public class SomeClass
{
internal static int StreamID
{
get
{
int returnValue;
if (HttpContext.Current != null)
{
if(HttpContext.Current.Items["StreamID"] != null)
{
returnValue = (int)HttpContext.Current.Items["StreamID"];
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
return returnValue;
}
}
}