2016-12-22 1 views
3

Tout d'abord, j'ai déjà recherché SO dans de nombreuses questions NullReferenceException. here et hereL'utilisation de tâches obtenant "Référence d'objet non définie sur une instance d'un objet"

Je reçois une erreur « référence d'objet non définie à une instance d'un objet » quand je tente d'appeler Task.WaitAll(tasks);

Je suis sûr que je l'initialisation des tous les objets avant d'essayer d'appeler des méthodes . Voici le code 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; 

    } 

NOTE

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

est le test où une exception est levée. var a = tasks.ToArray(); passe sans erreur.

exception est levée ici:

Task.WaitAll(a); 

et ici

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

Pouvez-vous me expliquer s'il vous plaît ce qui se passe? Je peux voir pendant le débogage que tasks est initialisé.

P.S. les lignes commentées par exemple: result.AddRange(GetResourceFreeBusyOnline(requesterId, meetingRoomIds.ToArray(), start, end)); sont les lignes appelant les méthodes dans un seul thread qui passe sans erreur et retourne le résultat attendu.

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

tâches ne génèrent pas les valeurs NULL. Renvoyer des valeurs nulles ou définir des variables sur null génère un résultat nul. Comme toujours, déboguez votre code, assurez-vous d'initialiser toutes les variables, etc –

+1

Au moins publier l'exception * full *, y compris sa pile d'appels. 'WaitAll' reprend presque certainement une exception lancée par l'une des tâches. En l'état, la question devrait probablement être fermée en tant que doublon. –

+0

question éditée (pile d'appel ajoutée) – pandemic

Répondre

1

Task.WaitAll ne jette pas cette exception. remettra les exceptions déclenchées par l'une de ses tâches. Sans l'exception complète et la pile d'appel (renvoyée par Exception.ToString()), il est impossible d'en être sûr, mais les instructions standard s'appliquent également ici: quelque part, une variable ou un paramètre non initialisé est utilisé.

Par exemple:

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

SplitResourceIds(resourceIds, out personIds, out meetingRoomIds); 

peut bien définir à la fois personIds et meetingRoomIds null. Cela signifie que

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

lancera une exception dans la tâche, qui sera à nouveau soulevée lorsque Task.WaitAll est appelé.

Pour résoudre ce problème, suivez les conseils donnés dans la question en double. Vérifiez les paramètres pour null, déboguer votre code, vérifiez la pile d'appel complète de l'exception. Task.WaitAll lancera un AggregateException qui contient toutes les exceptions sous-jacentes dans sa propriété InnerExceptions. À tout le moins, vous devez saisir le AggregateException pour gérer et consigner les exceptions déclenchées dans les tâches séparément.

Enfin, utilisez async/await, Task.Run et await Task.WhenAll au lieu de StartNew et Task.WaitAll.await déroule le AggregateException et déclenche l'exception sous-jacente, ce qui facilite considérablement le débogage.

MISE À JOUR

de la pile d'appel, il semble que les appels Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetMeetingRoomsFreeBusyCachedSharpArch.NHibernate.LinqRepositoryWithTypedId'2.FindAll et passe soit un paramètre nul ou une liste d'éléments contenant la valeur NULL. Ces valeurs sont probablement utilisées pour créer une clé de session, car SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey est appelée avant que l'exception soit levée.

Trouver le problème exact nécessite le débogage du code et entrer dans GetMeetingRoomsFreeBusyCached

+0

Merci, Vous m'avez montré le bon chemin et où trouver un problème. Nous créons la session NHIbernate comme une session qui n'était pas prête pour le multithread. J'ai donc dû mettre tout le code en sélectionnant DB en dehors des tâches. – pandemic

+0

Vous devriez envisager sérieusement de passer à EF ou un microORM comme Dapper. NHibernate a pris du retard car les opérations asynchrones nécessiteraient une réécriture complète. Vous ne pouvez pas simuler des opérations de base de données asynchrones avec des threads supplémentaires - les opérations asynchrones ADO.NET n'utilisent pas de threads, elles utilisent les ports d'achèvement des E/S du système d'exploitation pour fonctionner sans bloquer les threads. Au moins, assurez-vous que vous avez la [dernière version] (http://nhibernate.info/blog/) –