首先,我已经在很多NullReferenceException问题中搜索了SO。 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));
是在单个线程中调用方法的行,它在没有错误的情况下传递并返回预期结果。
堆栈
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()<---
答案 0 :(得分:1)
Task.WaitAll不会抛出此异常。它将重新抛出其任务之一引发的异常。没有完整的异常和调用堆栈(由EnumSet.noneOf()
返回),这是不可能确定的,但标准指南也适用于此 - 某处,某种程度上,使用了未初始化的变量或参数。
例如:
Exception.ToString()
可能会将List<int> personIds;
List<int> meetingRoomIds;
SplitResourceIds(resourceIds, out personIds, out meetingRoomIds);
和personIds
都设置为null。这意味着
meetingRoomIds
会在任务中抛出异常,在调用var task = Task.Factory.StartNew(() => GetResourceFreeBusyOnline(requesterId,
personIds.ToArray(),
start, end));
时会重新引发异常。
要解决此问题,请按照重复问题中的建议进行操作。检查参数是否为null,调试代码,检查异常的完整调用堆栈。 Task.WaitAll
将抛出AggregateException,其中包含InnerExceptions属性中的所有基础异常。
至少你应该抓住Task.WaitAll
来分别处理和记录任务中引发的异常。
最后,使用AggregateException
,async/await
和Task.Run
代替StartNew和Task.WaitAll。 await Task.WhenAll
打开await
并引发基础异常,这使调试变得更加容易。
<强>更新强>
在调用堆栈中,AggregateException
调用Tieto.MyMeetings.Tasks.FreeBusy.FreeBusyTasks.GetMeetingRoomsFreeBusyCached
并传递null参数或包含null的项列表。这些值可能用于创建会话密钥,因为在抛出异常之前会调用SharpArch.NHibernate.LinqRepositoryWithTypedId'2.FindAll
。
找到确切的问题需要调试代码并进入SharpArch.NHibernate.Web.Mvc.WebSessionStorage.GetSessionForKey