异步任务ASP.net HttpContext.Current.Items为空 - 如何处理这个?

时间:2014-08-14 04:17:36

标签: asp.net asynchronous task nullreferenceexception httpcontext

我们在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对象的副本 - 它只是一个浅拷贝而不是深拷贝。

2 个答案:

答案 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;
        }
    }
}

MSDN: system.web.httpcontext

答案 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;
        }
    }
}