使方法异步后 HttpContext.Current.Session null

Ric*_*cha 3 c# asp.net multithreading

我有一个像下面这样的方法

book.Bindbook();
Run Code Online (Sandbox Code Playgroud)

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

new Task(book.Bindbook).Start();
Run Code Online (Sandbox Code Playgroud)

现在,此方法使用 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*ner 5

您的解决方案存在很多潜在问题,导致了此问题。我将尝试将其分解为几个部分来解释发生了什么。

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

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

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

HttpContext不是线程安全的

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

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

静态属性通常是有害的

对象上具有静态属性要么意味着整个 AppDomain(例如TaskScheduler.Default)中恰好存在这些事物之一,它们代表一些可以配置的横切关注点,要​​么意味着存在一些隐藏的上下文操纵该值在幕后。前一种情况很少见,但在某些情况下是可以接受的,但第二种情况则相当有害。HttpContext.Current是一个不应该是静态的值的示例(ASP.NET 的未来版本完全废除了它)。它使代码难以推理,几乎无法测试,并且引入了不易处理的微妙错误(就像这个)。

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