我的UWP应用程序采取的第一个操作是检查包含数据的文件是否可用。如果是,它将尝试解密此数据并继续下一步,但如果加密文件已被调整或因抛出错误而损坏,我将尝试显示带有相关信息的消息对话框。
即使我已经100%确定事件链发生并且在相关位置受到try/catch
的保护,但它并没有抓住"更高的&#34 ;事件链中的那些,最终跳到
private void CoreApplication_UnhandledErrorDetected(object sender,
UnhandledErrorDetectedEventArgs ex)
我不明白为什么"更高" try/catch
没有抓住这个exception
?
可能是因为:
来自我的班级private async void
的{{1}}方法?
在我的constructor
创建我的DataService时生成了它,因为我正在使用MVVMLight创建服务?
无论如何都要显示来自ViewModelLocator
的消息对话框?我现在已经研究了一段时间,并且无法找到解决方案,因为我可以做到这一点。它抛出一个错误,说不允许这样做。
我还添加了CoreApplication_UnhandledErrorDetected
事件但未被触发。
处理应用程序启动时抛出的异常的最佳方法是什么?
更新-1:
我以为我提供了更多细节/代码,因为它仍然没有排序。
我实际上正在使用UnhandledException
/ IOC
来加密/解密数据。加密类本身(DI
)位于主应用程序中并实现了一个接口(EncryptionService
)。
IEncryptionService
类在EncryptionService
构造函数中第一次注入时创建DataService
类时创建了AppShellViewModel
对象:
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
的构造函数中,它通过调用静态方法即MyPCL
来创建Instance
的单个对象,并传递在EncryptionService
中创建的DataService
对象{1}}并传递给MyExternalService
。
如下所示,我在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
感谢。
UPDATE-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.
});
}
希望这有帮助。
答案 0 :(得分:1)
正如Henk提到的,每个异步方法都应该处理自己的异常。
如果您想显示异步方法中有关抛出异常的一些信息,您应该在UI线程上调用消息对话框,如下所示:
async void showMessageDialogMethod()
{
MessageDialog dialog = new MessageDialog("Sample message");
await dialog.ShowAsync();
}
await Dispatcher.RunAsync(CoreDispatcherPriority.High,
() => showMessageDialogMethod());