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)
您的解决方案存在很多潜在问题,导致了此问题。我将尝试将其分解为几个部分来解释发生了什么。
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 的未来版本完全废除了它)。它使代码难以推理,几乎无法测试,并且引入了不易处理的微妙错误(就像这个)。
从根本上来说,这是这里最大的问题,也是你痛苦的根本原因。如果此属性作为实例属性公开,并且该实例的范围仅限于请求上下文,那么您将不会遇到任何问题。一旦您使用的对象的生命周期与您的请求相同,您的所有关键状态都将变得本地化并且易于推理。
| 归档时间: |
|
| 查看次数: |
4615 次 |
| 最近记录: |