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.
Related
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.
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.
I've been noticing this exception in the CloudWatch logs for an AWS Lambda.
Everything seems to get processed so I think it is an exception within the AWS code (as opposed to something I've written) that is created after the Lambda has finished executing.
Since functionally it works I've been ignoring it but I'm concerned that there might be problems that I haven't noticed.
Lambda encountered an UnobservedTaskException via
'TaskScheduler.UnobservedTaskException' event:
{
"errorType": "AggregateException",
"errorMessage": "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. (Cannot access a disposed object.\nObject name: 'System.Net.Sockets.UdpClient'.)",
"cause": {
"errorType": "ObjectDisposedException",
"errorMessage": "Cannot access a disposed object.\nObject name: 'System.Net.Sockets.UdpClient'.",
"stackTrace": [
"at System.Net.Sockets.UdpClient.EndReceive(IAsyncResult asyncResult, IPEndPoint& remoteEP)",
"at System.Net.Sockets.UdpClient.<>c.<ReceiveAsync>b__56_1(IAsyncResult asyncResult)",
"at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)"
]
},
"causes": [ {
"errorType": "ObjectDisposedException",
"errorMessage": "Cannot access a disposed object.\nObject name: 'System.Net.Sockets.UdpClient'.",
"stackTrace": [
"at System.Net.Sockets.UdpClient.EndReceive(IAsyncResult asyncResult, IPEndPoint& remoteEP)",
"at System.Net.Sockets.UdpClient.<>c.<ReceiveAsync>b__56_1(IAsyncResult asyncResult)",
"at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)"
]
}]
}
The lambda code is pretty simple: It adds these SNS messages into an SQL database using Dapper.
I'm thinking that there might be some problem with how I'm doing async in the Fucntion handler. Any ideas?
public class Function
{
private static string _connectionString;
public async Task<IEnumerable<InsertSnsResult>> FunctionHandler(SNSEvent #event, ILambdaContext context)
{
try
{
context.Logger.LogLine("Adding SNS Messages");
_connectionString = _connectionString ?? await DecryptHelper.DecryptEnvironmentVariableAsync("ConnectionString").ConfigureAwait(false);
var handler = new AddSnsMessageHandler(new SnsMessagesRepository(_connectionString, context.Logger));
return await handler.AddSnsEvents(#event).ConfigureAwait(false);
}
catch (Exception e)
{
context.Logger.LogLine(e.Message);
throw;
}
finally
{
context.Logger.LogLine("Finished SNS Adding Messages");
}
}
}
[Edit]
Just be clear here, this exception does not get caught in the try/catch block. If it did it wouldn't be an UnobservedTaskException. That's why I'm having trouble getting to the root of the problem.
And this is the repository code
public async Task<List<InsertSnsResult>> InsertSnsMessages(IEnumerable<SnsEvent> records)
{
using (var connection = new SqlConnection(_connectionString))
{
await connection.OpenAsync().ConfigureAwait(false);
var results = new List<InsertSnsResult>();
foreach (var record in records)
{
try
{
await connection.ExecuteAsync(InsertEventCommand, record).ConfigureAwait(false);
results.Add(new InsertSnsResult(record.CorrelationId, true));
}
catch (Exception ex)
{
_logger.LogLine($"InsertSns failed for {record.Id}. {ex.Message}");
results.Add(new InsertSnsResult(record.CorrelationId, false));
}
}
return results;
}
}
The log messages are straightforward and explain what is happening:
You have an asynchronous task
That asynchronous task is accessing an object that has already been disposed, probably because you have some race condition in your workflow whereby an object in the asynchronous workflow is disposed out-of-order with another portion of the workflow that needs it. This means something is seriously broken in this workflow.
The asynchronous task is never waited on, either asynchronously with await, or (don't do this!) synchronously with Result or Wait. That means that the exceptional continuation path is never taken, and the task notices this when it is collected. Again, something is probably seriously broken in your workflow if you have a task that you never wait for the result. Combine this fact with the fact from the previous point: we now have two pieces of evidence that reinforce each other that there is something seriously broken in this workflow and that it involves a task that is not awaited when it should be to ensure an ordering constraint.
And therefore you get an exception on your finalizer thread, which is really bad.
Since functionally it works I've been ignoring it
I heard once that when a factory catches fire and burns to the ground, on average there were seven different safety systems that people ignored or disabled. Get out of this habit of thinking that it works, so it must be safe. Maybe it's nothing but I would consider these messages to be indicative of a serious problem until I had evidence otherwise.
I too have run into a place where I have a 3rd party library causing errors. I wanted log it outside of CloudWatch. In order to prevent Lambda from logging these I was able to do some evil reflection to reset the event handler.
Here is the code to do this yourself. Please note this is evil code. It is fragile and will break when code is changed in the CLR or even if the compiler does optimizations (which recently happened). However, it was the only way I could find to opt-out of this functionality provided by Lambda
private void ReplaceLambdaDefaultUnobservedTaskException()
{
try
{
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Static;
Type type = typeof(TaskScheduler);
var field = type.GetField("_unobservedTaskException", bindingFlags);
if (field == null)
{
field = type.GetField("UnobservedTaskException", bindingFlags);
}
var handler = new EventHandler<UnobservedTaskExceptionEventArgs>(TaskSchedulerOnUnobservedTaskException);
field.SetValue(null, handler);
}
catch (Exception ex)
{
logger.Warning(ex, "Unable to do evil reflection.");
}
TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;
}
private void TaskSchedulerOnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
e.SetObserved();
logger.Error(e.Exception, "Lambda threw an UnobservedTaskException");
}
I'm using Effort in a regular way by creating a connection and passing it to DB Context:
public class InMemoryContextInitializer
{
public void BeforeAllTests()
{
Effort.Provider.EffortProviderConfiguration.RegisterProvider();
}
public DbConnection BeforeEachTest()
{
return Effort.DbConnectionFactory.CreateTransient();
}
public void AfterEachTest(DbConnection prevUsedConnection)
{
prevUsedConnection.Dispose();
}
}
and something like this:
private static InMemoryContextInitializer _testHarness;
private DbConnection _conn;
private MyDbContext _myContext;
[ClassInitialize]
public static void BeforeAllTests(TestContext testCtx)
{
_testHarness = new InMemoryContextInitializer();
_testHarness.BeforeAllTests(); // registers provider
}
[TestInitialize]
public void BeforeTest()
{
_conn = _testHarness.BeforeEachTest();
_myContext = new MyDbContext(_conn);
}
[TestCleanup]
public void AfterTest()
{
_testHarness.AfterEachTest(_conn);
}
All my Effort tests pass just fine except one which throws this:
System.Data.DataException: An exception occurred while initializing the database. See the InnerException for details. --->
System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. --->
System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. --->
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. --->
NMemory.Exceptions.NMemoryException: Error code: GenericError --->
System.InvalidOperationException: Sequence contains more than one matching element
at System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source, Func`2 predicate)
at NMemory.Tables.TableCollection.FindTable(Type entityType)
at NMemory.Utilities.TableCollectionExtensions.FindTable(TableCollection tableCollection)
at NMemory.Execution.CommandExecutor.ExecuteInsert(T entity, IExecutionContext context)
at NMemory.Tables.DefaultTable`2.InsertCore(TEntity entity, Transaction transaction)
at Effort.Internal.DbManagement.Engine.ExtendedTable`2.InsertCore(TEntity entity, Transaction transaction)
at NMemory.Tables.Table`2.Insert(TEntity entity, Transaction transaction)
--- End of inner exception stack trace ---
at NMemory.Tables.Table`2.Insert(TEntity entity, Transaction transaction)
at Effort.Internal.Common.DatabaseReflectionHelper.WrapperMethods.InsertEntity(ITable`1 table, TEntity entity, Transaction transaction)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Effort.Internal.Common.DatabaseReflectionHelper.InsertEntity(ITable table, Object entity, Transaction transaction)
at Effort.Internal.CommandActions.InsertCommandAction.CreateAndInsertEntity(ITable table, IList`1 memberBindings, Transaction transaction)
at Effort.Internal.CommandActions.InsertCommandAction.ExecuteNonQuery(ActionContext context)
at Effort.Provider.EffortEntityCommand.ExecuteNonQuery()
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch(TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteNonQuery()
at System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues)
at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
--- End of inner exception stack trace ---
at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<Update>b__2(UpdateTranslator ut)
at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update(T noChangesResult, Func`2 updateFunction)
at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update()
at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__35()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction(Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass2a.<SaveChangesInternal>b__27()
at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute(Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
--- End of inner exception stack trace ---
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at System.Data.Entity.Migrations.History.HistoryRepository.BootstrapUsingEFProviderDdl(VersionedModel versionedModel)
at System.Data.Entity.Internal.InternalContext.<SaveMetadataToDatabase>b__7()
at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
at System.Data.Entity.Internal.InternalContext.SaveMetadataToDatabase()
at System.Data.Entity.Internal.DatabaseCreator.CreateDatabase(InternalContext internalContext, Func`3 createMigrator, ObjectContext objectContext)
at System.Data.Entity.Internal.InternalContext.CreateDatabase(ObjectContext objectContext, DatabaseExistenceState existenceState)
at System.Data.Entity.Database.Create(DatabaseExistenceState existenceState)
at System.Data.Entity.CreateDatabaseIfNotExists`1.InitializeDatabase(TContext context)
at System.Data.Entity.Internal.InternalContext.<>c__DisplayClassf`1.<CreateInitializationAction>b__e()
at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
--- End of inner exception stack trace ---
at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c)
at System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action)
at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.Count(IQueryable`1 source)
at Model.MyProj... my test method call stack here
I use multiple DB contexts in these tests and it all works except for this case:
var query = db.MyEntities.Count(); // will throw the exception above ONLY FOR SOME DB CONTEXTS
In fact any operation on this context like Add will throw.
I could not find anyone having the same problem on Effort website or by googling. Maybe it's a bug? I'm using the latest version of Effort - 1.1.4 and Entity Framework - 6.1.3.
I checked for any special thing about DbContext or the entity class and didn't find anything.
I had this issue and found that using a separate connection (Effort.DbConnectionFactory.CreatePersistent) for each context solved the issue.
In my case, each context operates over entirely different tables, so there shouldn't have been a conflict in Effort / NMemory - so I think the bug report is sound - but this information may unblock people in the meantime.
The trade off is that this could be warning you that you actually do have two contexts operating on the same table, which would be bad - so you'll have to watch out for this too.
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)