2016-12-22 2 views
3

Zuerst durchforstete ich SO in vielen NullReferenceException-Fragen. here und hereVerwendung von Tasks, die "Objektreferenz nicht auf eine Instanz eines Objekts gesetzt" erhalten

ich einen Fehler „Objektverweis auf eine Instanz eines Objekts nicht festgelegt“ bin immer wenn ich Task.WaitAll(tasks);

Ich bin sicher, rufen versuchen, dass ich die alle Objekte am initialisieren, bevor Sie versuchen Methoden aufrufen . Unten ist das Codestück:

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; 

    } 

HINWEIS

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

wird der Test, bei dem eine Ausnahme ausgelöst wird. var a = tasks.ToArray(); wird ohne Fehler übergeben.

Ausnahme ist hier geworfen:

Task.WaitAll(a); 

und hier

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

Können Sie mir bitte erklären, was passiert ist? Ich kann während des Debuggens sehen, dass tasks initialisiert wird.

P.S. Die kommentierten Zeilen, zum Beispiel: result.AddRange(GetResourceFreeBusyOnline(requesterId, meetingRoomIds.ToArray(), start, end));, sind die Zeilen, die die Methoden im einzelnen Thread aufrufen, die ohne Fehler übergeben werden und das erwartete Ergebnis zurückgeben.

Stapel

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

Aufgaben Schritt nicht NULL-Werte erzeugen. Die Rückgabe von Nullen oder das Setzen von Variablen auf null erzeugt null. Wie immer, Debuggen Sie Ihren Code, stellen Sie sicher, dass Sie alle Variablen usw. initialisieren –

+1

Mindestens Post die * vollständige * Ausnahme, einschließlich seiner Aufrufliste. 'WaitAll' wiederholt mit ziemlicher Sicherheit eine Ausnahme, die von einer der Aufgaben ausgelöst wurde. So wie es ist, sollte die Frage wahrscheinlich als ein Duplikat geschlossen werden. –

+0

Frage bearbeitet (Anrufliste hinzugefügt) – pandemic

Antwort

1

Task.WaitAll diese Ausnahme nicht werfen. Es wird Ausnahmen erneut auslösen, die von einer seiner Aufgaben ausgelöst werden. Ohne die vollständige Ausnahme und den Aufrufstack (wie von Exception.ToString() zurückgegeben) ist es unmöglich, sicher zu sein, aber die Standardanleitung gilt auch hier - irgendwo wird irgendwie eine nicht initialisierte Variable oder ein Parameter verwendet.

Zum Beispiel:

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

SplitResourceIds(resourceIds, out personIds, out meetingRoomIds); 

können auch beide personIds und meetingRoomIds auf null gesetzt. Das bedeutet, dass

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

eine Ausnahme in der Aufgabe werfen, die wieder angehoben werden, wenn Task.WaitAll genannt wird.

Um dies zu beheben, folgen Sie einfach den Anweisungen in der Duplikatsfrage. Überprüfen Sie die Parameter auf null, debuggen Sie den Code, überprüfen Sie den gesamten Aufruf-Stack der Ausnahme. Task.WaitAll wird eine AggregateException werfen, die alle zugrunde liegenden Ausnahmen in seiner InnerExceptions Eigenschaft enthält.

Zumindest sollten Sie die AggregateException fangen, um in Aufgaben aufgeworfene Ausnahmen separat zu behandeln und zu protokollieren.

Verwenden Sie schließlich async/await, Task.Run und await Task.WhenAll anstelle von StartNew und Task.WaitAll.await wickelt die AggregateException aus und löst die zugrunde liegende Ausnahme aus, was das Debugging erheblich vereinfacht.

UPDATE

Aus dem Call-Stack scheint es, dass Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetMeetingRoomsFreeBusyCached Anrufe SharpArch.NHibernate.LinqRepositoryWithTypedId'2.FindAll und entweder einen Null-Parameter oder eine Liste der Elemente geht, die null enthalten. Diese Werte werden wahrscheinlich zum Erstellen eines Sitzungsschlüssels verwendet, da SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey aufgerufen wird, bevor die Ausnahme ausgelöst wird.

das genaue Problem zu finden erfordert den Code debuggen und in GetMeetingRoomsFreeBusyCached

+0

Danke, Sie haben mir den richtigen Weg gezeigt und wo Sie ein Problem finden können. Wir erstellen die NHIbernate-Sitzung als eine Sitzung, die nicht für Multithread bereit ist. Also musste ich den gesamten Code aus der DB außerhalb von Tasks setzen. – pandemic

+0

Sie sollten ernsthaft in Erwägung ziehen, zu EF oder einer microORM wie Dapper zu wechseln. NHibernate ist zurückgefallen, da asynchrone Operationen eine vollständige Neuschreibung erfordern würden. Sie können keine asynchronen Datenbankoperationen mit zusätzlichen Threads fälschen - ADO.NET-asynchrone Operationen verwenden keine Threads. Sie verwenden die IO-Completion-Ports des Betriebssystems, um ohne Threads zu blockieren. Stellen Sie zumindest sicher, dass Sie die [neueste Version] haben (http://nhibernate.info/blog/) –

Verwandte Themen