在使方法异步后,HttpContext.Current.Session为null

时间:2015-09-22 07:08:38

标签: c# asp.net multithreading

我有一个类似下面的方法

book.Bindbook();

我将其设为异步,如下所示

new Task(book.Bindbook).Start();

现在这个方法使用HttpContext.Current.Session,它现在返回null。 这是返回null的代码

public static Bookmanager CartManager
{
    //Gets the value from the session variable.
    get
    {
        try
        {
            if (HttpContext.Current.Session["BookData"] == null)
            {
                Bookmanager bookmgr= new Bookmanager ();
                Book book = new Book(SessionManager.CurrentUser);
                bookmgr.SetCurrentCart(book);                       
                HttpContext.Current.Session["BookData"] = bookmgr;
            }
            else if (((Bookmanager)HttpContext.Current.Session["BookData"]).GetCurrentCart() == null)
            {
                Book book = new Book(SessionManager.CurrentUser);
                ((Bookmanager)HttpContext.Current.Session["BookData"]).SetCurrentCart(book);
            }
        }
        catch(Exception ex)
        {
            //throw ex;
        }
        return ((Bookmanager)HttpContext.Current.Session["BookData"]);
    }
    //Sets the value of the session variable.
    set
    {
        HttpContext.Current.Session["BookData"] = value;
    }
}

3 个答案:

答案 0 :(得分:2)

您的解决方案存在许多可能导致此问题的潜在问题。我会尝试将其分解成碎片来解释发生了什么。

new Task(book.Bindbook).Start()并不总是在您认为的地方运行

这种创建异步操作的方法非常危险,因为不容易知道如何执行任务。当您调用此构造函数时,Task将捕获TaskScheduler.Current值作为它将用于安排自己执行的机制。这意味着您的任务的执行与其所处的上下文无关。

通常,您希望使用Task.Run(Action)而不是创建新的Task实例,然后调用Start,因为它始终以TaskScheduler.Default的值运行,这是HttpContext通常是.NET线程池,通常是您在运行后台任务时要执行的操作。

HttpContext不是线程安全的

Current类从未打算从多个线程安全地调用。它的HttpContext值与正在处理请求的线程相关联,并且在其他线程上不可用。你不应该把它传递给其他线程。一般来说,您应该将应用程序中Current的表面积减少到最低限度。它几乎不可能为了测试目的而进行模拟,并且有一些微妙的限制(例如你发现),这使得使用它具有挑战性。

相反,请在代码中尽早显示TaskScheduler.Default值,并保留对实际需要使用的对象的引用(如会话)。

静态属性通常是有害的

在对象上拥有静态属性意味着对于整个AppDomain(例如HttpContext.Current),这些东西中只有一个代表了一些可以配置的交叉问题,或者有一些隐藏的上下文操纵幕后的价值。前一种情况很少见,但在某些情况下可以接受,但第二种情况非常有害。 <p:panel id="mypanel" widgetVar="mypanelWidget" header="A title here" toggleable="true" toggleOrientation="vertical" collapsed="true"> 是一个不应该是静态值的示例(ASP.NET的未来版本完全取消它)。它使得代码难以推理,几乎不可能测试并引入容易处理的微妙错误(比如这个)。

从根本上说,这是这里最大的问题,也是你痛苦的根本原因。如果此属性作为实例属性公开,并且实例的范围限定为请求上下文,则不会出现任何问题。一旦您使用的生命周期与您的请求相同,您的所有关键状态都将变为本地且易于推理。

答案 1 :(得分:1)

使用ConfigureAwait(true)允许在原始上下文上继续。

var task = new Task(() => book.Bindbook()).ConfigureAwait(true);

task.Start();

答案 2 :(得分:0)

HttpContext绑定到thread,这就是null的原因。 我认为更好的解决方案是将所有需要的数据通过参数传递给其他线程,而不是共享HttpContext