我的UWP应用程序采取的第一个操作是检查包含数据的文件是否可用.如果是,它将尝试解密此数据并继续下一步但我正在尝试显示带有相关信息的消息对话框,如果加密文件已被调整或被抛出错误而损坏.
即使我认为我对事件链发生了100%肯定并且它们在相关位置受到try / catch的保护,但它并没有捕获事件链中的“更高”事件,并最终跳转到
private void CoreApplication_UnhandledErrorDetected(object sender,
UnhandledErrorDetectedEventArgs ex)
我不明白为什么“更高”的try / catch没有捕获这个异常?
可能因为:
>它来自我的类构造函数调用的私有异步void方法?
>当我在我的ViewModelLocator中创建DataService时,它是在我创建服务时生成的,因为我正在使用MVVMLight?
无论如何都要从CoreApplication_UnhandledErrorDetected显示一个消息对话框?我已经研究了一段时间了,无法找到解决方案,因为我能做到这一点.这是一个错误,说这是不允许的.
我还添加了UnhandledException事件,但是没有被触发.
处理应用程序启动时抛出的异常的最佳方法是什么?
更新1:
我以为我会提供更多细节/代码,因为它仍然没有排序.
我实际上正在使用IOC / DI来加密/解密数据.加密类本身(EncryptionService)位于主应用程序中并实现了一个接口(IEncryptionService).
在我的DataService类第一次在AppShellViewModel的构造函数中注入时创建了一个EncryptionService对象:
AppShellViewModel
public class AppShellViewModel
{
public AppShellViewModel(IDataservice data)
{
....
}
}
DataService的:
internal class DataService : IDataService
{
public DataService()
{
this.myExternalService = new MyExternalService(new EncryptionService());
}
}
MyExternalService
internal sealed class MyExternalService
{
public class MyExternalService(IEncryptionService encryptionService)
{
this.MyPcl = MyPCL.Instance(encryptionService);
}
internal MyPCL MyPcl {get; set;}
}
如您所见,当IDataService注入我的AppShellViewModel类时,它会创建DataService类,而后者将创建我的新EncryptionService ojbect(基于IEncryptionService)并将其传递给MyExternalService类.
在MyExternalService的构造函数中,它通过调用静态方法(即Instance)创建MyPCL的单个对象,并传递在DataService中创建并传递给MyExternalService的EncryptionService对象.
如下所示,我在MyPCL的构造函数中读取了我的设置.一旦创建了单例对象,就会发生这种情况.它读取设置,然后尝试使用从我的应用程序传递的EncryptionService对象解密数据,并实现IEncryptionService.
public class MyPCL
{
private readonly IEncryptionService _encryptionService;
public MyPCL(IEncryptionService encryptionService)
{
this._encryptionService = encryptionService;
ReadSettingsData();
}
public static MyPCL Instance(IEncryptionService encryptionService)
{
if (null == _instance)
{
lock (SingletonLock)
{
if (null == _instance)
{
_instance = new MyPCL(this._encryptionService);
}
}
}
return _instance;
}
private async void ReadSettingsData()
{
await ReadSettings();
}
private async Task ReadSettings()
{
IFolder folder = FileSystem.Current.LocalStorage;
IFile file = folder.GetFileAsync("MyFile.txt").Result;
string data = await file.ReadAllTextAsync().Result;
if (!string.IsEmptyOrNull(data))
{
data = await this._encryptionService.DecryptAsync(data);
}
}
}
现在在我的主应用程序中,EncryptionService使用Windows.Security.Cryptography.DataProtection,我有2个函数.正在进行异步调用的加密和解密. Decrypt函数定义如下:
public async Task<string> DecryptAsync(string encryptedText)
{
var provider = new DataProtectionProvider("LOCAL = user");
IBuffer data = CryptographicBuffer.DecodeFromHexString(encryptedText);
IBuffer decryptedBuffer = await provider.UnprotectAsync(data);
return await Task.FromResult(CryptographicBuffer.ConvertBinaryToString
(BinaryStringEncoding.Utf8, decryptedBuffer));
}
好吧,我认为上述内容虽然简化,但却代表了它的要点.
当它试图通过调用来解密调节数据时:
IBuffer decryptedBuffer = await provider.UnprotectAsync(data);
它是抛出错误的地方,但是如何抓住它并显示出错的地方并采取特定的行动?
我现在已经删除了所有错误处理程序,我希望你们中的一个会告诉我我需要把它放在哪里,因为DataService,MyExternalPcl和MyPCL中的每个函数都有错误处理,它仍然被轰炸并转到CoreApplication_UnhandledErrorDetected
谢谢.
更新2:
好吧,它需要相当多的麻烦才能最终找到正确的方法来解决这个问题,但Henk确实让我朝着正确的方向前进.
我的第一个问题,与我的问题中描述的不同,我使用了Protect和Unprotect的同步功能.这同样适用于我的加密/解密功能.我更改了它们以使用Protect和Unprotect的异步功能,并将Decrypt和Encrypt都修改为DecryptAsync / EncryptAsync并确保它们返回Task.
这可能听起来像一个小东西,但这必须修复或它导致我的应用程序锁定/挂起.
我根据这篇文章中的建议更改了下一部分Catch an exception thrown by an async method,(谢谢Henk!)是我从构造函数中调用异步方法的方法.
而不是调用我的ReadSettingsData方法,这是一个虚拟的void方法,因为我可以从我的构造函数中调用ReadSettings,我直接调用了ReadSetting,但如下所示:
public MyPCL(IEncryptionService encryptionService)
{
this._encryptionService = encryptionService;
ReadSettingsData().Wait();
}
注意.Wait().完成后,我终于能够捕获异常并将其推回到我的事件链中,一直回到我的应用程序并显示一条消息并采取适当的操作.
由于这是我们的应用程序的一个严重错误,并且永远不会发生,我确保引入一个特定的异常,即EncryptionServiceException,它被捕获在ReadSettings中并相应地被抛回.
由于我没有在任何其他地方放置任何try / catch,它被从MyExternalPcl库推回到我的应用程序,但它不是常规异常,而是作为AggregateException返回,但这可以很容易地按照本文处理:How to: Handle Exceptions Thrown by Tasks但是这是核心片段:
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is UnauthorizedAccessException) // This we know how to handle.
{
Console.WriteLine("You do not have permission to access
all folders in this path.");
Console.WriteLine("See your network administrator or try
another path.");
return true;
}
return false; // Let anything else stop the application.
});
}
希望这可以帮助.
解决方法:
正如Henk提到的,每个异步方法都应该处理自己的异常.
如果您想显示异步方法中有关抛出异常的一些信息,您应该在UI线程上调用消息对话框,如下所示:
async void showMessageDialogMethod()
{
MessageDialog dialog = new MessageDialog("Sample message");
await dialog.ShowAsync();
}
await Dispatcher.RunAsync(CoreDispatcherPriority.High,
() => showMessageDialogMethod());