2016-12-22 7 views
3

Прежде всего, я уже просматривал SO во многих вопросах NullReferenceException. here и hereИспользование задач получения «Ссылка на объект не установлена ​​на экземпляр объекта»

Я получаю сообщение об ошибке «Ссылка на объект не указывает на экземпляр объекта», когда я пытаюсь вызвать Task.WaitAll(tasks);

Я уверен, что я инициализируются все объекты, прежде чем пытаться вызвать методы , Ниже приведен код snipet:

public IList<ResourceFreeBusyDto> GetResourceFreeBusy(int requesterId, int[] resourceIds, DateTime start, DateTime end) 
    { 
     IList<ResourceFreeBusyDto> result = new List<ResourceFreeBusyDto>(); 

     ValidateFreeBusyInputs(resourceIds, start, end); 

     List<Task<IList<ResourceFreeBusyDto>>> tasks = new List<Task<IList<ResourceFreeBusyDto>>>(); 
     TimeSpan timeout = new TimeSpan(0,0,30); // 30 seconds   

     // Split resources to persons and meetingRooms 
     List<int> personIds; 
     List<int> meetingRoomIds; 

     SplitResourceIds(resourceIds, out personIds, out meetingRoomIds); 

     // Go online for persons 
     if (personIds.Count > 0) 
     { 
      //result.AddRange(GetResourceFreeBusyOnline(requesterId, personIds.ToArray(), start, end)); // paralelizovat 
      Task<IList<ResourceFreeBusyDto>> task = Task.Factory.StartNew(() => GetResourceFreeBusyOnline(requesterId, personIds.ToArray(), start, end)); 
      tasks.Add(task); 
     } 

     // Go online for meetingrooms if they are not cached in DB 
     if (meetingRoomIds.Count > 0) 
     { 
      DateTime? lastModifiedMeetingRoomFreeBusy = new DateTime(); 

      lastModifiedMeetingRoomFreeBusy = freeBusyRepository.GetMinTimeStamp(); 

      if (lastModifiedMeetingRoomFreeBusy.Value.AddMinutes(1) < DateTime.UtcNow || lastModifiedMeetingRoomFreeBusy == null) 
      { 
       //result.AddRange(GetResourceFreeBusyOnline(requesterId, meetingRoomIds.ToArray(), start, end)); // mrIDs 
       Task<IList<ResourceFreeBusyDto>> task = Task.Factory.StartNew(() => GetResourceFreeBusyOnline(requesterId, resourceIds, start, end)); 
       tasks.Add(task); 
      } 
      else 
      { 
       //result.AddRange(GetMeetingRoomsFreeBusyCached(requesterId, meetingRoomIds.ToArray(), start, end)); // mrIDs 
       Task<IList<ResourceFreeBusyDto>> task = Task.Factory.StartNew(() => GetMeetingRoomsFreeBusyCached(requesterId, resourceIds, start, end)); 
       tasks.Add(task); 
      } 
     } 

     bool status = false; 

     try 
     { 
      var a = tasks.ToArray(); 
      Task.WaitAll(a); 
      status = Task.WaitAll(tasks.ToArray(), timeout); 
     } 
     catch (Exception ex) 
     { 

      Log.Fatal(ex); 
     } 


     if (status == false) 
     { 
      throw new ApplicationException(
      string.Format("Timeout expired." + 
      " The timeout period elapsed prior to completion of the asynchronous importing task executing" + 
      " or the server is not responding. Try it later!")); 
     } 
     else 
     { 
      foreach (Task<IList<ResourceFreeBusyDto>> task in tasks) 
      { 
       result.AddRange(task.Result); 
      } 
     } 

     return result; 

    } 

ПРИМЕЧАНИЕ

var a = tasks.ToArray(); 
Task.WaitAll(a); 

является тест, где выброшено исключение. var a = tasks.ToArray(); проходит без ошибок.

Исключение брошено здесь:

Task.WaitAll(a); 

и здесь

status = Task.WaitAll(tasks.ToArray(), timeout); 

Можете ли вы объяснить мне, что происходит? Во время отладки можно увидеть, что инициализируется tasks.

P.S. например, строки с комментариями: result.AddRange(GetResourceFreeBusyOnline(requesterId, meetingRoomIds.ToArray(), start, end)); - это строки, вызывающие методы в одном потоке, которые передаются без ошибок и возвращают ожидаемый результат.

Stack

2016-12-22 13:24:18,844 [9] FATAL Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks - System.AggregateException: One or more errors occurred. ---> System.NullReferenceException: Object reference not set to an instance of an object. 
    at SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSimpleSessionStorage() 
    at SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey(String factoryKey) 
    at SharpArch.NHibernate.NHibernateSession.CurrentFor(String factoryKey) 
    at SharpArch.NHibernate.NHibernateRepositoryWithTypedId`2.get_Session() 
    at SharpArch.NHibernate.LinqRepositoryWithTypedId`2.FindAll() 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetResourceFreeBusyOnline(Int32 requesterId, Int32[] resourceIds, DateTime start, DateTime end) in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 238 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.<>c__DisplayClass7_0.<GetResourceFreeBusy>b__0() in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 83 
    at System.Threading.Tasks.Task`1.InnerInvoke() 
    at System.Threading.Tasks.Task.Execute() 
    --- End of inner exception stack trace --- 
    at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeout, CancellationToken cancellationToken) 
    at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeout) 
    at System.Threading.Tasks.Task.WaitAll(Task[] tasks) 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetResourceFreeBusy(Int32 requesterId, Int32[] resourceIds, DateTime start, DateTime end) in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 113 
---> (Inner Exception #0) System.NullReferenceException: Object reference not set to an instance of an object. 
    at SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSimpleSessionStorage() 
    at SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey(String factoryKey) 
    at SharpArch.NHibernate.NHibernateSession.CurrentFor(String factoryKey) 
    at SharpArch.NHibernate.NHibernateRepositoryWithTypedId`2.get_Session() 
    at SharpArch.NHibernate.LinqRepositoryWithTypedId`2.FindAll() 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetResourceFreeBusyOnline(Int32 requesterId, Int32[] resourceIds, DateTime start, DateTime end) in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 238 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.<>c__DisplayClass7_0.<GetResourceFreeBusy>b__0() in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 83 
    at System.Threading.Tasks.Task`1.InnerInvoke() 
    at System.Threading.Tasks.Task.Execute()<--- 

---> (Inner Exception #1) System.NullReferenceException: Object reference not set to an instance of an object. 
    at SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSimpleSessionStorage() 
    at SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey(String factoryKey) 
    at SharpArch.NHibernate.NHibernateSession.CurrentFor(String factoryKey) 
    at SharpArch.NHibernate.NHibernateRepositoryWithTypedId`2.get_Session() 
    at SharpArch.NHibernate.LinqRepositoryWithTypedId`2.FindAll(ILinqSpecification`1 specification) 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetMeetingRoomsFreeBusyCached(Int32 requesterId, Int32[] meetingRoomIds, DateTime start, DateTime end) in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 196 
    at Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.<>c__DisplayClass7_0.<GetResourceFreeBusy>b__2() in C:\_Hg\Tieto.MyMeetings\source\server\Tieto.MyMeetings.Tasks\FreeBusy\FreeBusyTasks.cs:line 103 
    at System.Threading.Tasks.Task`1.InnerInvoke() 
    at System.Threading.Tasks.Task.Execute()<--- 
+4

Задачи не генерируют аннулирует. Возврат nulls или установка переменных в null порождает null. Как всегда, отлаживайте свой код, убедитесь, что вы инициализируете все переменные и т. Д. –

+1

По крайней мере, отправьте * полное * исключение, включая стек вызовов. 'WaitAll' почти наверняка реконструирует исключение, вызванное одной из задач. Как бы то ни было, вопрос, вероятно, должен быть закрыт как дубликат. –

+0

вопрос отредактирован (добавлен стек вызовов) – pandemic

ответ

1

Task.WaitAll не бросает это исключение. Это будет исключений ретрона, поднятых одной из его задач. Без полного исключения и стека вызовов (как возвращено Exception.ToString()) невозможно быть уверенным, но здесь также применяется стандартное руководство - где-то, как-то, используется неинициализированная переменная или параметр.

Например:

List<int> personIds; 
List<int> meetingRoomIds; 

SplitResourceIds(resourceIds, out personIds, out meetingRoomIds); 

может также установить как personIds и meetingRoomIds к нулю. Это означает, что

var task = Task.Factory.StartNew(() => GetResourceFreeBusyOnline(requesterId, 
                   personIds.ToArray(), 
                   start, end)); 

сгенерирует исключение внутри задачи, которая будет вновь поднят, когда Task.WaitAll называется.

Чтобы исправить это, просто следуйте рекомендациям по дублирующему вопросу. Проверьте параметры для null, отлаживайте свой код, проверяйте полный стек вызовов исключения. Task.WaitAll выдает AggregateException, содержащий все основные исключения в своем InnerExceptions.

По крайней мере, вы должны поймать AggregateException для обработки и регистрации исключений, поднятых в задачах отдельно.

Наконец, используйте async/await, Task.Run и await Task.WhenAll вместо StartNew и Task.WaitAll.await распаковывает AggregateException и создает основное исключение, что облегчает отладку.

UPDATE

Из стека вызовов оказывается, что Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetMeetingRoomsFreeBusyCached вызовы SharpArch.NHibernate.LinqRepositoryWithTypedId'2.FindAll и проходит либо нулевой параметр или список элементов, содержащих нуль. Эти значения, вероятно, используются для создания ключа сеанса, так как SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey вызывается до того, как будет выбрано исключение.

Нахождение точной задачи требует отладки кода и заходя в GetMeetingRoomsFreeBusyCached

+0

Спасибо, ты показал мне правильный путь и где найти проблему. Мы создаем сессию NHIbernate как сессию, которая не была готова к многопоточности. Поэтому мне пришлось выставить весь код, выбрав из базы данных вне задач. – pandemic

+0

Вам следует серьезно подумать о переходе на EF или в микроморе, например Dapper. NHibernate отстает, поскольку асинхронные операции потребуют полной перезаписи. Вы не можете подделывать операции асинхронной базы данных с дополнительными потоками. Асинхронные операции ADO.NET не используют потоки, они используют порты завершения ввода-вывода операционной системы для работы без блокировки любых потоков. По крайней мере, убедитесь, что у вас есть [последняя версия] (http://nhibernate.info/blog/) –