Reputation: 2939
I would like to capture all unhandled exception in my Xamarin PCL (portable class library), but cant figure out how to hook up the UnhandledException method?
I can see I can do it in the windows(device) specific project; but not in the PCL?
I am basically trying to use the PCLStorage to log errors but this is blocking me.
I have also tried using a dependency service to write via a non PCL approach. When an error is thrown it is caught by the App.gi.cs file which is auto generated. Its then propagate to UnhandledException method that I have hooked up the window 8.1 project.
I have tried to use the dependency service to write to a file, but due to the code being async think it is exiting before it can write the logs, as it is an unhandled exception.
await DependencyService.Get<IFileWriter>().ErrorAsync(e.Exception);
Is there a way to write to a file in a non async manner as async seems to be all over the place; making this rather difficult.
Upvotes: 0
Views: 5915
Reputation: 2939
I got it working by blocking the main thread from existing until the logs had been written. This was done from Windows Project for the main App.xaml.cs file.
The main bits to take note of are the ManualResetEvent object and the calling of the WaitOne and Set methods which will block and resume the main thread.
I had to store the exception in a variable too, as it was loosing the stack trace if I used the e.Exception directly in the anonymous async method.
private static readonly ManualResetEvent resetEvent = new ManualResetEvent(false);
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.UnhandledException += (sender, e) =>
{
var exception = e.Exception;
Task.Run(async () =>
{
await DependencyService.Get<IFileWriter>().ErrorAsync(exception);
resetEvent.Set();
});
resetEvent.WaitOne();
};
}
For more completeness I have included the DependencyService Window's project code method that writes to the local storage.
private async Task WriteToLogFile(string message, string messageType)
{
var storageFolder = await GetStorageFolder();
var file = await storageFolder.CreateFileAsync(FormatDateForLogName(), CreationCollisionOption.OpenIfExists);
try
{
using (StreamWriter writer = new StreamWriter(await file.OpenStreamForWriteAsync(), Encoding.UTF8))
{
writer.BaseStream.Seek(writer.BaseStream.Length, SeekOrigin.Begin);
writer.Write(string.Format("{0}{1} - {2}: {3}", System.Environment.NewLine, FormatLogPrefix(), messageType, message));
}
}
catch (Exception err)
{
System.Diagnostics.Debug.WriteLine(err.Message);
}
}
private async Task<StorageFolder> GetStorageFolder()
{
StorageFolder local = ApplicationData.Current.LocalFolder;
return await local.CreateFolderAsync(LogFolderName, CreationCollisionOption.OpenIfExists);
}
Upvotes: -1
Reputation: 12585
Try this:
TaskScheduler.UnobservedTaskException += (s, e) =>
{
Mvx.Error("Task exception from {0}: {1}", s.GetType(), e.Exception.ToString());
if (!e.Observed)
e.SetObserved();
};
This only works in the final app project, but will catch all exceptions triggered by your PCL libs too.
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
{
var ex = e.ExceptionObject as Exception;
Mvx.Error("Domain Exception from {0}: {1}", s.GetType(), ex != null ? ex.ToString() : e.ToString());
};
Upvotes: 2