[英]C#: Adding context to Parallel.ForEach() in ASP.NET
我有一个带静态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
}
在视图使用此属性之前,此静态类不会进行类型初始化。
问题是,在Parallel.ForEach()
创建new Promotion()
时初始化的Promotion
的静态构造函数使用HttpContext.Current
。 当promo
在此Parallel.ForEach()
的范围内实例化时, HttpContext.Current
为null
,因此new Promotion()
会导致异常。
HttpContext.Current
在静态get属性中不为null,因为在视图使用它之前不会调用它(因此它有一个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为null,因为它在“非Web线程”中运行。 如果你使用new Thread(...)
分叉一些代码,它将完全相同。 TPL在某种程度上隐藏了这一点,但您仍然需要意识到Parallel.ForEach
中的每次迭代都可能在不同的线程中运行,并相应地对其进行处理。
特别是,如果你想在web请求中使用某些类或方法(并且Parallel.ForEach就是这种用法),你就是不能使用HttpContext.Current。 解决方法是在构造函数中显式传递HttpContext(或HttpContextBase以提高可测试性)(或作为方法参数)
简而言之:你需要静态地使用HttpContext.Current。
只需将Parallel.ForEach调用之外的任何上下文传递给依赖于所述上下文的内部调用的任何函数。
var context = HttpContext.Current;
Parallel.ForEach(items, item =>
{
DoSomething(item, context);
}
);
private static void DoSomething(item, context = null) {
if (context == null) context = HttpContext.Current;
...
}
我喜欢回退到null,所以我不必担心一直在传递上下文。 我只确保记住我的函数在从另一个线程调用时需要上下文,然后我就把那个孩子打到了那里。
它不起作用,因为在foreach中创建了一个新线程,因此上下文为null。 即使创建一个方法DoSomething来设置当前上下文,上下文仍然是null。
正如Mauricio指出的那样, HttpContext.Current
依赖于当前正在执行的线程。 让我感到不同的是, 静态构造函数依赖于HttpContext.Current
这样一个固有的瞬态值,但也许这不是你的想法。
如果您可以更改Promotion
类,那么这将是我考虑的第一个选项。
如果没有,您需要以某种方式强制Promotion
在HttpContext.Current
仍然有效的点上进行类型初始化。 要了解强制类型初始化的内容,请阅读此Jon Skeet博客文章 。
一个选项可能是创建一个虚拟的Promotion
对象,(在整个程序中只需一次就足够了)。 如果这不是一个选项,您可以尝试通过反射阅读该属性。 我不知道是否强制类型初始化,但我想是的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.