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

标签 c# asp.net multithreading parallel-processing

我有一个带有静态 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.Currentnull,并且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.CurrentParallel.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/

相关文章:

java - 哲学家就餐 - 最后一个线程未正确终止

c# - 如何播种随机类以避免获得重复的随机值

c# - 可轻松与 C# 和 .NET 一起使用的 winforms 替代品

c# - 需要帮助为 Asp.net MVC 构建自定义 Html Helper

asp.net - XSLT - 使用带有副本的子字符串来保留内部 HTML 标记

ASP.NET 站点通过 SSL 从 Visual Studio 而不是 IIS 连接到远程

c# - 尝试将项目和值添加到 asp.net 中的下拉列表时出错

multithreading - Delphi DLL - 线程安全

c++ - QThread 和 QPainter::drawText() 的 Qt/C++ 内存泄漏

c# - DataContext 绑定(bind)和刷新