Parallel.ForEach错误HttpContext.Current

时间:2014-11-03 09:11:01

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

这种方法 - 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);
    }

}


这是错误 this error i am getting

会出现什么问题?为什么我得到Session null。什么是解决方法

4 个答案:

答案 0 :(得分:19)

每个线程设置

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

这里有几个来源已经涵盖了这个问题。

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

HttpContext.Current.Items in different thread

Access HttpContext.Current from different threads

答案 1 :(得分:2)

您收到错误是因为您试图从未运行的线程中获取HttpContext以响应请求。

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

您需要在调用方法时传递方法所需的信息。

答案 2 :(得分:2)

HttpContext.Current为null,因为它在“非Web线程”中运行。如果你使用新的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) {
}

答案 3 :(得分:1)

进一步加入Bayu Alvian的回答。我有一个类似的问题,我通过传递上下文作为参数,但在我得到的方法

内解决了它

会员&#39;方法名称&#39;无法使用实例引用访问

我通过对上述答案进行一些调整解决了这个问题。

// 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会将其删除。