C# HttpContext.Current.Session使方法异步后为null

C# HttpContext.Current.Session使方法异步后为null,c#,asp.net,multithreading,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

我有一个如下的方法

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

HttpContext
绑定到
线程
,这就是为什么它是
null

我认为更好的解决方案是通过参数将所有需要的数据传递给其他线程,而不是共享
HttpContext

您的解决方案中有很多潜在的问题导致了这个问题。我会试着把它分成几部分来解释发生了什么

新任务(book.Bindbook).Start()
并不总是在您认为它可以运行的地方运行

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

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

HttpContext
不是线程安全的

从未打算从多个线程安全地调用
HttpContext
类。它是绑定到正在处理请求的线程的
当前值,在其他线程上不可用。您不应该将其传递给其他线程。一般来说,您应该将应用程序中的
HttpContext
的表面积减少到最小。出于测试目的,几乎不可能对其进行模拟,并且存在一些微妙的限制(如您正在发现的),这使得使用它具有挑战性

相反,应尽早在代码中显示
当前值
,并保留对实际需要处理的对象(如会话)的引用

静态特性通常是有害的

在对象上具有静态属性意味着整个AppDomain(例如
TaskScheduler.Default
)中正好有一个这样的东西,它们表示可以配置的一些横切关注点,或者有一些隐藏的上下文在幕后操纵值。前一种情况很少见,但在某些情况下可以接受,但第二种情况相当有害
HttpContext.Current
是一个不应该是静态的值的示例(ASP.NET的未来版本将完全取消它)。它使代码难以推理,几乎不可能测试,并引入了不易处理的微妙错误(如本例)

从根本上说,这是这里最大的问题,也是你痛苦的根源。如果此属性作为实例属性公开,并且实例的作用域为请求上下文,那么您就不会有任何问题。一旦您使用的对象的生存期与您的请求相同,您的所有关键状态都将变为本地状态,并且易于推理。

使用ConfigureWait(true)允许在原始上下文中继续

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

task.Start();

实际上,您只是在一个
任务中调用了这个方法。这并不能使方法本身
异步。