Xamarin.Forms PopModalAsync: A Task's exception(s) were not observed - c#

I have the following Code:
System.Threading.Tasks.Task appointmentEndTask = App.ArdaBusinessLogic.AppointmentEnd(_appointment);
System.Threading.Tasks.Task appointmentEndCompletedTask = appointmentEndTask.ContinueWith(
async task =>
{
_appointmentDetailPage.IsDirty = true;
await App.MasterNavigationPage.Navigation.PopModalAsync();
},
System.Threading.CancellationToken.None,
System.Threading.Tasks.TaskContinuationOptions.OnlyOnRanToCompletion,
System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
System.Threading.Tasks.Task appointmentEndFaultedTask = appointmentEndTask.ContinueWith(
async task =>
{
await App.MasterNavigationPage.Navigation.PopModalAsync();
await App.ShowErrorPageAsync(task.Exception);
},
System.Threading.CancellationToken.None,
System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted,
System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
So if the "AppointmentEnd"-Task completes the current Modal-Page should be closed. From time to time (not always!) i get the following error in my crash logs. Linenumber 139 is "await App.MasterNavigationPage.Navigation.PopModalAsync()" after "_appointmentDetailPage.IsDirty = true" in this case.
Xamarin caused by: android.runtime.JavaProxyThrowable:
System.AggregateException: A Task's exception(s) were not observed
either by Waiting on the Task or accessing its Exception property. As
a result, the unobserved exception was rethrown by the finalizer
thread. ---System.ArgumentOutOfRangeException: Index was out of
range. Must be non-negative and less than the size of the collection.
Parameter name: index at
System.Collections.Generic.List`1[T].get_Item (System.Int32 index)
[0x00009] in
/Users/builder/jenkins/workspace/xamarin-android-d15-9/xamarin-android/external/mono/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:180
at Xamarin.Forms.Application+NavigationImpl+<OnPopModal>d__2.MoveNext
() [0x00022] in D:\a\1\s\Xamarin.Forms.Core\Application.cs:381
--- End of stack trace from previous location where exception was thrown --- at
CPM.Arda.Mobile.Freelancer.Ui.Pages.Appointment.Complete+<<confirmButton_Clicked>b__5_0>d.MoveNext
() [0x0007d] in
D:\ProjekteTFVC\ArdaMobileFreelancer\SourceCode\Ui\1.0\Pages\Appointment\Complete.xaml.cs:139
--- End of inner exception stack trace ---
---(Inner Exception #0) System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the
collection. Parameter name: index at
System.Collections.Generic.List`1[T].get_Item (System.Int32 index)
[0x00009] in
/Users/builder/jenkins/workspace/xamarin-android-d15-9/xamarin-android/external/mono/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:180
at Xamarin.Forms.Application+NavigationImpl+<OnPopModal>d__2.MoveNext
() [0x00022] in D:\a\1\s\Xamarin.Forms.Core\Application.cs:381
--- End of stack trace from previous location where exception was thrown --- at
CPM.Arda.Mobile.Freelancer.Ui.Pages.Appointment.Complete+<<confirmButton_Clicked>b__5_0>d.MoveNext
() [0x0007d] in
D:\ProjekteTFVC\ArdaMobileFreelancer\SourceCode\Ui\1.0\Pages\Appointment\Complete.xaml.cs:139
Unfortunately, I do not understand how it can come to this error. Can you help me?

First, why are you using such a complicated syntax instead of taking advantage of async await?
public async void EndAppointement()
{
try
{
await App.ArdaBusinessLogic.AppointmentEnd(_appointment);
_appointmentDetailPage.IsDirty = true;
await App.MasterNavigationPage.Navigation.PopModalAsync();
}
catch (Exception exception)
{
await App.MasterNavigationPage.Navigation.PopModalAsync();
await App.ShowErrorPageAsync(exception);
}
}
Second, looking at XF source code:
protected override async Task<Page> OnPopModal(bool animated)
{
Page modal = ModalStack[ModalStack.Count - 1];
if (_owner.OnModalPopping(modal))
{
_owner.OnPopCanceled();
return null;
}
Page result = await base.OnPopModal(animated);
result.Parent = null;
_owner.OnModalPopped(result);
return result;
}
It seems that your modal stack is messed up: meaning you are trying to pop pages that are not on the stack. Are you sure you're on a modal page? Maybe use PopAsync instead of PopModalAsync.

Related

WebView2 throws timeout Exception while initialization for some users

My webview2 initialization doesn't work for some group of users, But for some it works properly. It throws an timeout exception for some users.
Below is my code-
public async Task InitializeAsync()
{
EnsureTemplate();
Browser.NavigationStarting += Browser_NavigationStarting;
Browser.NavigationCompleted += Browser_NavigationCompleted;
Browser.PreviewKeyDown += Browser_PreviewKeyDown;
Browser.CoreWebView2InitializationCompleted += Browser_CoreWebView2InitializationCompleted;
var cachePath = WebUIConfigSection.Current.AbsoluteCachePath;
var environment = await CoreWebView2Environment.CreateAsync(null, cachePath, null);
await Browser.EnsureCoreWebView2Async(environment);
}
Exception details-
Type: System.Runtime.InteropServices.COMException
Target site: Void ThrowExceptionForHRInternal(Int32, IntPtr)
Message: This operation returned because the timeout period expired. (HRESULT: 0x800705B4)
Source: mscorlib
Stacktrace:
vid System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) vid Microsoft.Web.WebView2.Core.CoreWebView2Environment.d__54.MoveNext() vid System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() vid System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) vid Microsoft.Web.WebView2.Wpf.WebView2.<>c__DisplayClass27_0.<g__Init|0>d.MoveNext()
What I did to avoid the exception is to set a timer that does a .Stop() when the query exceeded a certain time (configurable).
You could use the same to determine how long it takes WebView to timeout.
I assume that the target page is not using frames.

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()<---
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

Unobserved exception was rethrown despite awaiting the Task and catching Exception

I have code that catches all exceptions that are thrown by a server call as follows:
new public Task SaveAsync()
{
return ServerException.Wrap(base.SaveAsync);
}
Where ServerException.Wrap looks like:
public static async Task<T> Wrap<T>(Func<Task<T>> func)
{
try
{
return await func();
}
catch (Exception ex)
{
// This is an internal error that shouldn't happen.
throw new ServerException(ex);
}
}
public static async Task Wrap(Func<Task> func)
{
await Wrap(async () =>
{
await func();
return true;
});
}
And then I have a function that calls SaveAsync as follows:
try
{
await problem.SaveAsync();
}
catch (ServerException ex)
{
Logger.LogException("Error saving problem.", ex);
}
I have some internal error that generates an exception which I catch in the above line and then it gets logged as follows:
2015-10-20 11:20:44.502 [Line 99] Error saving problem. (Exception:
Exceptions.ServerException: ---> System.ArgumentException: An item
with the same key has already been added. at
System.ThrowHelper.ThrowArgumentException (ExceptionResource resource)
[0x00000] in
/Users/builder/data/lanes/1977/2c66d2fe/source/mono/external/referencesource/mscorlib/system/throwhelper.cs:74
However a few seconds later I get an unhanded exception warning that gets logged:
2015-10-20 11:21:16.352 Warning: Unhandled exception:
System.AggregateException: A Task's exception(s) were not observed
either by Waiting on the Task or accessing its Exception property. As
a result, the unobserved exception was rethrown by the finalizer
thread. ---> System.ArgumentException: An item with the same key has
already been added. at System.ThrowHelper.ThrowArgumentException
(ExceptionResource resource) [0x00000] in
/Users/builder/data/lanes/1977/2c66d2fe/source/mono/external/referencesource/mscorlib/system/throwhelper.cs:74
Why do I get the second unobserved exception, even though I am catching and handling the first exception? This exception seems to be thrown by my ServerException.Wrap method.
I am using MonoTouch.
You need to explicitly set the exception to observed.
For that, you need to subscribe to the TaskScheduler's UnobservedTaskException event, and set it explicitly to observed (call SetObserved() on it).
See here:
UnobservedTaskException being throw...
EDIT:
Of course, you can also just catch AggregateException as well, or use ContinueWith() to observe and resume the task.
See the bottom of the official documentation:
Exception Handling (MSDN)

System.AggregateException on Socket.EndAccept with TaskFactory.FromAsync

I am working with async operations with sockets (.Net 4 - VS 2010 SP1) and all seems to be working okay. However, after write and run an automated test, it pass green but displays an exception message:
---- UNHANDLED EXCEPTION ----
Thread Name: <No Name>
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndAccept(IAsyncResult asyncResult)
at P2PNet.Listener.<ListenForConnections>b__0(IAsyncResult r) in C:\Users\lucas.ontivero\Documents\Visual Studio 2010\Projects\P2PNet\P2PNet\Listener.cs:line 76
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)
--- End of inner exception stack trace ---
at System.Threading.Tasks.TaskExceptionHolder.Finalize()
---> (Inner Exception #0) System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndAccept(IAsyncResult asyncResult)
at P2PNet.Listener.<ListenForConnections>b__0(IAsyncResult r) in C:\Users\lucas.ontivero\Documents\Visual Studio 2010\Projects\P2PNet\P2PNet\Listener.cs:line 76
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)<---
I know what that exception means, it means the socket was closed before the EndAccept method was called. I have no problems with that, what I really don´t know is how to prevent that exception in an elegant way. This is my code:
private void ListenForConnections()
{
try
{
Task.Factory.FromAsync<Socket>(_listener.BeginAccept, _listener.EndAccept, _listener)
.ContinueWith(task =>
{
if (task.IsFaulted) return;
ListenForConnections();
var newSocket = task.Result;
RaiseClientConnectedEvent(new ConnectionEventArgs(newSocket));
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
catch (ObjectDisposedException)
{
}
I´ve tried with the line:
if (task.IsFaulted) return;
and also with:
.ContinueWith(task=>{}, TaskContinuation.OnlyOnFault);
But the exception is thrown anyway. Which is the way to prevent the exception?
Thank you!
Your line:
if (task.IsFaulted) return;
Is returning not faulted because you are checking the continuation task's status, not the preceding task. Change it to this:
private void ListenForConnections() {
Task<Socket> listentask = Task.Factory.FromAsync<Socket>(_listener.BeginAccept, _listener.EndAccept, _listener);
listentask.ContinueWith(task => {
if (listentask.IsFaulted) {
//observe exception
Exception exception = listentask.Exception;
return;
}
ListenForConnections();
var newSocket = listentask.Result;
RaiseClientConnectedEvent(new ConnectionEventArgs(newSocket));
});
//don't forget to start it
listentask.Start();
}
You need to observe the exception by reading the Exception property. Do that inside of your continuation.

What causes a System.Runtime.InteropServices.COMException at BackgroundAudioPlayer.get_Position()?

Sometimes I'm getting an exception when trying to get the position of the BackgroundAudioPlayer.Instance. It's happening very rarely, but I've been able to get a StackTrace. The strange thing is, this code is executed every second while playing a track. What could be the cause of this error?
I'm getting this StackTrace.
System.SystemException: HRESULT = 0xC00D36C4 ---> System.Runtime.InteropServices.COMException: Exception from HRESULT: 0xC00D36C4 at
Microsoft.Phone.BackgroundAudio.Interop.IAudioPlaybackManager.get_CurrentPosition() at
Microsoft.Phone.BackgroundAudio.BackgroundAudioPlayer.get_Position() --- End of inner exception stack trace --- at
Microsoft.Phone.BackgroundAudio.BackgroundAudioPlayer.get_Position() at
MC.PodCast.Common.ViewModel.PlayerViewModel.UpdateTrackPosition() at
MC.PodCast.Common.ViewModel.PlayerViewModel.ReactToBackgroundAudioPlayer() at
MC.PodCast.Common.ViewModel.PlayerViewModel.Initialize() at
MC.PodCast.Common.ViewModel.PlayerViewModel.<<get_InitializeCommand>b__5>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__0(Object state)
Of course the code I'm using is just plain simple.
public void UpdateTrackPosition()
{
if (_backgroundAudioPlayer != null && _backgroundAudioPlayer.Track != null)
{
Position = _backgroundAudioPlayer.Position;
}
else
{
Position = null;
}
}
That code is linked to MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED but I'm guessing that you do have sound.
I have found that the BackgroundAudioPlyer can be very weird. I wrap most of my calls with a "Safe" extension method.
Example
public static PlayState PlayerStateSafe(this BackgroundAudioPlayer source)
{
PlayState state;
try
{
state = source.PlayerState;
}
catch (InvalidOperationException)
{
state = PlayState.Unknown;
}
return state;
}

Categories

Resources