C#:向ASP.NET中的Parallel.ForEach()添加上下文

我有一个带静态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.Currentnull ,因此new Promotion()会导致exception。

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.CurrentParallel.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,所以我不必担心一直在传递上下文。 我只确保记住我的函数在从另一个线程调用时需要上下文,然后我在那里拍了那个宝贝。

正如Mauricio所指出的, HttpContext.Current依赖于当前正在执行的线程。 静态构造函数依赖于HttpContext.Current这样一个固有的瞬态值,这让我觉得很不寻常,但也许这不是你的想法。

如果您可以更改Promotion类,那么这将是我考虑的第一个选项。

如果没有,您需要以某种方式强制PromotionHttpContext.Current仍然有效的点上进行类型初始化。 要了解强制类型初始化的内容,请阅读此Jon Skeet博客文章 。

一个选项可能是创建一个虚拟的Promotion对象,(在整个程序中只需一次即可)。 如果这不是一个选项,您可以尝试通过reflection读取属性。 我不知道是否强制类型初始化,但我想是的。

它不起作用,因为在foreach中创建了一个新线程,因此上下文为null。 即使创建一个方法DoSomething来设置当前上下文,上下文仍然是null。