在UWP中处理未处理的异常 - Windows 10

时间:2016-05-24 13:31:28

标签: c# win-universal-app uwp

我的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.
    });

}

希望这有帮助。

1 个答案:

答案 0 :(得分:1)

正如Henk提到的,每个异步方法都应该处理自己的异常。

如果您想显示异步方法中有关抛出异常的一些信息,您应该在UI线程上调用消息对话框,如下所示:

async void showMessageDialogMethod()
    {
        MessageDialog dialog = new MessageDialog("Sample message");
        await dialog.ShowAsync();
    }


await Dispatcher.RunAsync(CoreDispatcherPriority.High,
                       () => showMessageDialogMethod());