Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using tasks getting "Object reference not set to an instance of an object"

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()<---
like image 772
pandemic Avatar asked Oct 17 '22 20:10

pandemic


1 Answers

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

like image 177
Panagiotis Kanavos Avatar answered Oct 21 '22 06:10

Panagiotis Kanavos