2014-11-03 2 views
6

Этот метод - doDayBegin(item.BranchId) занимает много времени для выполнения. Поэтому я использую Parallel.ForEach, чтобы выполнить его параллельно. Когда я использую обычный цикл foreach, он работает нормально, но когда я использую Parallel.ForEach, он показывает эту ошибку.
Ссылка на объект не установлена ​​в экземпляр объекта.Ошибка Parallel.ForEach HttpContext.Current

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. каков способ ее решения

ответ

19

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

1

Вы получаете ошибку, потому что вы пытаетесь получить HttpContext из потока, который не работает с целью ответа на запрос.

Свойство HttpContext.Current использует поток, чтобы определить, какой контекст получить, поскольку веб-сервер может запускать несколько потоков для обработки запросов. Поскольку Parallel.ForEach запускает новые потоки, они не будут подключены к HttpContext.

Вам необходимо передать информацию, необходимую методу в вызове метода.

2

HttpContext.Current - null, потому что он работает в «не-веб-потоках». Если вы разветвляете какой-то код с помощью нового Thread (...), он будет точно таким же. TPL несколько скрывает это, но вам все равно нужно понять, что каждая итерация в Parallel.ForEach может потенциально запускаться в другом потоке и обрабатывать ее соответствующим образом.

В частности, если вы хотите использовать какой-либо класс или метод из веб-запроса (и Parallel.ForEach - такое использование), вы просто не можете использовать HttpContext.Current. Чтобы обойти проблему, явным образом передать HttpContext (или HttpContextBase для улучшения проверяемости) в конструктор (или в качестве параметра метода)

пример:

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



private static void DoSomething(HttpContext context) { 
} 
0

Далее добавляя к Баю Alvian ответа. У меня была аналогичная проблема, и я решил его передачей контекста в качестве параметра, но внутри метода я получил

«имя метода» пользователя не могут быть доступны с экземпляром ссылки

Я решил его, делая немного подправить от приведенный выше ответ.

// 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 удаляет его.