first of all, I already searched through SO in many NullReferenceException questions. here and here
I am getting an error "Object reference not set to an instance of an object" when I try to call Task.WaitAll(tasks);
I am sure that I am initializing the all the objects before trying to call methods. Below is the 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);
is the test where an exception is thrown. var a = tasks.ToArray();
is passing without an error.
Exception is thrown here:
Task.WaitAll(a);
and here
status = Task.WaitAll(tasks.ToArray(), timeout);
Can you please explain me what is happening? I can see during the debugging that tasks
is initialized.
P.S. the commented lines for example: result.AddRange(GetResourceFreeBusyOnline(requesterId, meetingRoomIds.ToArray(), start, end));
are the lines calling the methods in single thread which is passing without an error and returning the expected result.
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()<---
Task.WaitAll doesn't throw this exception. It will rethrow exceptions raised by one of its tasks. Without the full exception and call stack (as returned by Exception.ToString()
) it's impossible to be sure, but the standard guidance applies here as well - somewhere, somehow, an unininitialized variable or parameter is used.
For example:
List<int> personIds;
List<int> meetingRoomIds;
SplitResourceIds(resourceIds, out personIds, out meetingRoomIds);
may well set both personIds
and meetingRoomIds
to null. This means that
var task = Task.Factory.StartNew(() => GetResourceFreeBusyOnline(requesterId,
personIds.ToArray(),
start, end));
will throw an exception inside the task, that will be re-raised when Task.WaitAll
is called.
To fix this just follow the advice in the duplicate question. Check parameters for null, debug your code, check the full call stack of the exception. Task.WaitAll
will throw an AggregateException which contains all underlying exceptions in its InnerExceptions property.
At the very least you should catch the AggregateException
to handle and log exceptions raised in tasks separately.
Finally, use async/await
, Task.Run
and await Task.WhenAll
instead of StartNew and Task.WaitAll. await
unwraps the AggregateException
and raises the underlying exception, which makes debugging a lot easier.
UPDATE
From the call stack it appears that Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetMeetingRoomsFreeBusyCached
calls SharpArch.NHibernate.LinqRepositoryWithTypedId'2.FindAll
and either passes a null parameter or a list of items that contain null. These values are probably used to create a session key, since SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey
is called before the exception is thrown.
Finding the exact problem requires debugging the code and stepping into GetMeetingRoomsFreeBusyCached
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With