我想在我的Xamarin PCL(可移植类库)中捕获所有未处理的异常,但是无法弄清楚如何连接 UnhandledException 方法?
我可以看到我可以在windows(设备)特定项目中完成它;但不是在PCL中?
我基本上是尝试使用PCLStorage来记录错误,但这阻止了我。
我还尝试使用依赖服务通过非PCL方法进行写入。 当抛出错误时,它会被自动生成的 App.gi.cs 文件捕获。然后它传播到UnhandledException方法,我已经连接了窗口8.1项目。
我曾尝试使用依赖服务写入文件,但由于代码是异步的,因此认为它在写入日志之前就已退出,因为它是一个未处理的异常。
await DependencyService.Get<IFileWriter>().ErrorAsync(e.Exception);
有没有办法以非异步方式写入文件,因为async似乎到处都是;使这很困难。
答案 0 :(得分:2)
试试这个:
TaskScheduler.UnobservedTaskException += (s, e) =>
{
Mvx.Error("Task exception from {0}: {1}", s.GetType(), e.Exception.ToString());
if (!e.Observed)
e.SetObserved();
};
这仅适用于最终的应用程序项目,但也会捕获由PCL库触发的所有异常。
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());
};
答案 1 :(得分:-1)
我通过阻止主线程从现有开始直到写入日志为止。这是通过Windows Project为主 App.xaml.cs 文件完成的。
需要注意的主要内容是 ManualResetEvent 对象以及调用 WaitOne 和设置方法,这些方法将阻止并恢复主线。
我不得不将异常存储在变量中,因为如果我在匿名异步方法中直接使用 e.Exception ,它就会丢失堆栈跟踪。
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();
};
}
为了更完整,我已经包含了写入本地存储的DependencyService Window项目代码方法。
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);
}