我有一个带有静态 get 属性的静态类,在这个属性中,我这样做:
// property body
{
// HttpContext.Current is NOT null
...
Parallel.ForEach(files, file =>
{
// HttpContext.Current is null
var promo = new Promotion();
...
});
...
// HttpContext.Current is NOT null
}
在 View 使用此属性之前,此静态类不会进行类型初始化。
问题在于 Promotion
的静态构造函数,它是在 Parallel.ForEach() 中第一次创建
,使用 new Promotion()
时初始化的HttpContext.Current
。当 promo
在此 Parallel.ForEach()
范围内实例化时,HttpContext.Current
为 null
,并且new Promotion()
因此导致异常。
HttpContext.Current
在静态 get 属性中不为空,因为在 View 使用它之前不会调用它(因此有一个 HttpContext.Current
)。
如果 Promotion
在其实例中使用 HttpContext.Current
而不是静态成员,我可能只需将 HttpContext.Current
传递到 new Promotion()
构造函数:
var context = HttpContext.Current;
Parallel.ForEach(files, file =>
{
var promo = new Promotion(context);
});
但是由于 Promotion 的 static
成员需要 HttpContext.Current,所以我不能。我可能可以重新设计 Promotion
类,以将需要它的静态成员更改为实例成员,但它们是静态的是有原因的——如果所有成员都是静态的,将会有很大的性能损失每次实例化 new Promotion
时,都必须在每个实例上定义。
对此有哪些可能的解决方法?我没有意识到 HttpContext.Current
在 Parallel.ForEach()
的范围内会为 null。
最佳答案
HttpContext.Current 为空,因为它在“非网络线程”中运行。如果您使用 new Thread(...)
fork 一些代码,它会完全一样。 TPL 在某种程度上隐藏了这一点,但您仍然需要意识到 Parallel.ForEach
中的每次迭代都可能在不同的线程中运行,并相应地对待它。
特别是,如果您想使用 Web 请求之外的某些类或方法(Parallel.ForEach 就是这样一种用法),您就不能使用 HttpContext.Current。解决方法是在构造函数中显式传递 HttpContext(或 HttpContextBase 以提高可测试性)(或作为方法参数)
简而言之:您需要停止静态使用 HttpContext.Current。
关于C#:在 ASP.NET 中向 Parallel.ForEach() 添加上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3790817/