【问题标题】:Parallel.ForEach error HttpContext.CurrentParallel.ForEach 错误 HttpContext.Current
【发布时间】:2014-11-03 09:11:01
【问题描述】:

此方法 - doDayBegin(item.BranchId) 需要很长时间才能执行。所以我使用Parallel.ForEach 来并行执行它。当我使用正常的foreach 循环时,它工作正常,但是当我使用Parallel.ForEach 时,它显示此错误
对象引用未设置为对象的实例。

 public ActionResult Edit([DataSourceRequest] DataSourceRequest request)
        {
            try
            {
                JavaScriptSerializer js = new JavaScriptSerializer();
                List<DB0010020Vm> _listDB0010020Vm = new List<DB0010020Vm>();

                string dataDB0010020vm = Request.Form["griddetailsvm"];
                if (!string.IsNullOrEmpty(dataDB0010020vm))
                {
                    _listDB0010020Vm = js.Deserialize<List<DB0010020Vm>>(dataDB0010020vm).
                    Where(d => d.IsValid == "YES").ToList();
                }
                DateTime start = DateTime.UtcNow;


                Parallel.ForEach(_listDB0010020Vm, item =>
                {
                    doDayBegin(item.BranchId);
                });

                DateTime end = DateTime.UtcNow;
                TimeSpan duration = end - start;
                return Json(new
                {
                    success = true,
                    message = "Day Begin Process Completed Successfully!" + duration
                });
            }
            catch (Exception e)
            {
                return Json(new
                {
                    success = false,
                    message = e.Message
                });

            }
        }

  public void doDayBegin(int BranchId)
{
    var httpContext = System.Web.HttpContext.Current;
    IDB0010020Repository _idDB0010020Repository = new DB0010020Repository();
    IDB0010044Repository _idDB0010044Repository = new DB0010044Repository();

     EBS.DAL.Model.DB0010020 branchDetails = _idDB0010020Repository.FindOne(d => d.BranchId == BranchId);
    if (branchDetails == null)
    {
        ModelState.AddModelError("", "Branch not found!");
    }
    else
    {
        try
        {
            DateTime LastOpenDate = DateTime.ParseExact(Request.Form["LastOpenDate"].ToString(), "dd/MM/yyyy", CultureInfo.InvariantCulture);
         //   branchDetails.LastOpenDate = LastOpenDate;
    //      branchDetails.LastOpenDate = Convert.ToDateTime(Request.Form["LastOpenDate"].ToString());


        }
        catch (Exception e)
        {
          //  branchDetails.LastOpenDate = Convert.ToDateTime("2014-07-25 00:00:00.000");
        }


        OperationStatus status = _idDB0010020Repository.UpdateAndSave(branchDetails);
        if (status != null && !status.Status)
            ModelState.AddModelError("Updation failed", status.ExceptionMessage);
    }

    EBS.DAL.Model.DB0010044 dayBegin = new DB0010044();
    dayBegin.BankId = 1;
    dayBegin.BranchId = BranchId;
    dayBegin.DayBeginFlag = 1;
    //added d
    DateTime DayDate = DateTime.ParseExact(Request.Form["LastOpenDate"].ToString(), "dd/MM/yyyy", CultureInfo.InvariantCulture);
    dayBegin.DayDate = DayDate;
    //added d

  //  dayBegin.DayDate = Convert.ToDateTime(Request.Form["LastOpenDate"]);
    dayBegin.DayEndFlag = 0;
    dayBegin.DayEndStage = 1;
    dayBegin.DayReopenFlag = 0;
    OperationStatus status2 = _idDB0010044Repository.AddAndSave(dayBegin);
    if (status2 != null && !status2.Status)
        ModelState.AddModelError("Updation failed", status2.ExceptionMessage);
    else
    {
        CreateInwardSessionsForBranch(BranchId);
        CreateOutwardSessionsForBranch(BranchId);
    }

}


这是错误

会有什么问题?为什么我得到 Session 为空。有什么办法解决

【问题讨论】:

    标签: c# asp.net-mvc linq entity-framework parallel-processing


    【解决方案1】:

    HttpContext.Current 是按线程设置的。因此,当您使用Parallel.ForEach 启动更多线程时,您的新线程无法以这种方式访问​​它。解决方案是将所需的值作为参数一直传递,而不是依赖存储库中的HttpContext.Current

    这里有几个关于 SO 的资料已经涵盖了这个问题。

    The cross-thread usage of "HttpContext.Current" property and related things

    HttpContext.Current.Items in different thread

    Access HttpContext.Current from different threads

    【讨论】:

      【解决方案2】:

      您收到错误是因为您试图从一个没有运行以响应请求的线程获取HttpContext

      HttpContext.Current 属性使用线程来识别要获取的上下文,因为 Web 服务器可以运行多个线程来处理请求。当Parallel.ForEach 启动新线程时,它们不会连接到HttpContext

      您需要在对方法的调用中传递该方法所需的信息。

      【讨论】:

        【解决方案3】:

        HttpContext.Current 为 null,因为它在“非 Web 线程”中运行。如果您使用 new Thread(...) 分叉一些代码,那将是完全相同的。 TPL 在某种程度上隐藏了这一点,但您仍然需要意识到 Parallel.ForEach 中的每次迭代都可能在不同的线程中运行,并相应地处理它。

        特别是,如果您想在 Web 请求之外使用某些类或方法(Parallel.ForEach 就是这样一种用法),您就不能使用 HttpContext.Current。一种解决方法是在构造函数(或作为方法参数)中显式传递 HttpContext(或 HttpContextBase 以提高可测试性)

        示例:

        var context = HttpContext.Current;
        Parallel.ForEach(items, item =>
            {
                DoSomething(context);
            }
        );
        
        
        
        private static void DoSomething(HttpContext context) {
        }
        

        【讨论】:

          【解决方案4】:

          进一步添加到巴渝阿尔维安的答案。我有一个类似的问题,我通过将上下文作为参数传递但在我得到的方法内部解决了它

          无法使用实例引用访问成员“方法名称”

          我通过对上述答案进行一些调整来解决它。

          // Get the new context
          HttpContext context = HttpContext.Current;
          Parallel.ForEach(items, item =>
              {
                  DoSomething(context);
              }
          );
          
          private static void DoSomething(HttpContext context) {
           HttpContext.Current = context;
          }
          

          将上下文分配给 HttpContext.Current 会删除它。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-11-18
            • 1970-01-01
            • 2014-12-29
            • 1970-01-01
            • 1970-01-01
            • 2013-07-31
            • 2012-07-06
            相关资源
            最近更新 更多