Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel.ForEach error HttpContext.Current

this method - doDayBegin(item.BranchId) is taking long time to execute. So I am using Parallel.ForEach to execute it parallel. When I am using normal foreach loop its working fine but when i am using Parallel.ForEach it showing this error
Object reference not set to an instance of an object.

 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 is error this error i am getting

what will be the issue? why i am getting Session null. what is way to solve it

like image 835
dvirus Avatar asked Nov 03 '14 09:11

dvirus


4 Answers

You get the error because you are trying to get the HttpContext from a thread that is not running for the purpose of responding to a request.

The HttpContext.Current property uses the thread to identify which context to get, as the web server can run several threads to handle requests. As the Parallel.ForEach starts new threads, they will not be connected to a HttpContext.

You need to pass along the information that the method needs in the call to the method.

like image 169
Guffa Avatar answered Sep 22 '22 04:09

Guffa


Further adding to Bayu Alvian answer. I had a similar problem and I solved it by passing the context as parameter but inside the method I got

Member 'method name' cannot be accessed with an instance reference

I solved it by doing a little tweak from the above answer.

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

private static void DoSomething(HttpContext context) {
 HttpContext.Current = context;
}

Assigning the context to the HttpContext.Current removes it.

like image 44
Vikneshwar Avatar answered Sep 23 '22 04:09

Vikneshwar


HttpContext.Current is set per thread. So when you fire up more threads using Parallel.ForEach your new threads can't access it that way. The solution would be to pass the needed values as parameters all the way instead of relying on HttpContext.Current in your repositories.

There are several sources here on SO that covers this problem already.

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

HttpContext.Current.Items in different thread

Access HttpContext.Current from different threads

like image 32
Karl-Johan Sjögren Avatar answered Sep 22 '22 04:09

Karl-Johan Sjögren


HttpContext.Current is null because it's running in "non-web threads". If you forked some code using new Thread(...) it would be exactly the same. The TPL somewhat hides this, but you still need to realize that each iteration in your Parallel.ForEach can potentially run in a different thread, and treat it accordingly.

In particular, if you want to use some class or method out of the web request (and Parallel.ForEach is such an usage) you just can't use HttpContext.Current. A workaround is to explicitly pass the HttpContext (or HttpContextBase for improved testability) in the constructor (or as a method parameter)

example :

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



private static void DoSomething(HttpContext context) {
}
like image 34
Bayu Alvian Avatar answered Sep 22 '22 04:09

Bayu Alvian