【问题标题】:Handling unhandled exception in UWP - Windows 10在 UWP 中处理未处理的异常 - Windows 10
【发布时间】:2016-05-26 18:22:46
【问题描述】:

我的 UWP 应用执行的第一个操作是检查包含数据的文件是否可用。如果是,它将尝试解密此数据并继续下一步,但如果加密文件已被修改或因抛出错误而损坏,我将尝试显示一个包含相关信息的消息对话框。

即使我认为我 100% 肯定会发生事件链并且它们在相关位置受到 try/catch 的保护,但它并没有捕捉到事件链中“更高”的事件,它最终会跳转到

private void CoreApplication_UnhandledErrorDetected(object sender,
UnhandledErrorDetectedEventArgs ex)

我不明白为什么“更高”的try/catch 没有抓住这个exception

可能是因为:

  • 它来自我的班级constructor调用的private async void方法?

  • 它是在我的 ViewModelLocator 中创建我的 DataService 时生成的,它在我使用 MVVMLight 时创建服务?

是否可以显示来自CoreApplication_UnhandledErrorDetected 的消息对话框?我已经研究了一段时间,但找不到解决方案,因为我可以做到这一点。它抛出一个错误,说这是不允许的。

我还添加了UnhandledException 事件,但没有被触发。

处理应用程序启动时抛出的异常的最佳方法是什么?

更新 1:

我想我会提供更多详细信息/代码,因为它仍未排序。

我实际上是在使用IOC/DI 来加密/解密数据。加密类本身 (EncryptionService) 在主应用程序中并实现了一个接口 (IEncryptionService)。

当我的DataService 类第一次被注入AppShellViewModel 的构造函数时,会创建一个EncryptionService 对象:

AppShellViewModel

public class AppShellViewModel
{
    public AppShellViewModel(IDataservice data)
    {
       ....
    }
}

数据服务:

internal class DataService : IDataService
{
  public DataService()
  {
      this.myExternalService = new MyExternalService(new EncryptionService());
  }
}

我的外部服务

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的单例对象,并将EncryptionService对象传递给DataService中创建并传递给@987654353 @。

如下所示,我在MyPCL 的构造函数中读取了我的设置。一旦创建了单例对象,就会发生这种情况。它读取设置,然后尝试使用从我的应用程序传递并实现IEncryptionServiceEncryptionService 对象解密数据。

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);

这是它抛出错误的地方,这很好,但我如何捕捉它并显示出现问题并采取特定行动??

我现在已经删除了所有错误处理程序,我希望你们中的一个能告诉我我需要把它放在哪里CoreApplication_UnhandledErrorDetected

谢谢。

UPDATE-2:

好的,最终找到正确的处理方法需要相当多的时间,但 Henk 确实让我朝着正确的方向前进。

我的第一个问题,与我的问题中描述的不同,我使用同步功能进行保护和取消保护。这同样适用于我的加密/解密功能。我将它们都更改为使用 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 但这是核心 sn-p:

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

}

希望这会有所帮助。

【问题讨论】:

  • @HenkHolterman 我认为你可能是对的。我已经添加了 .Wait() 并且它确实改善了一些事情。我现在生成了一个我可以处理的聚合异常,现在我的 UnhandledException 也被触发了,我可以决定做什么。我明天会做更多检查并确认,但我认为你可能是对的。谢谢。
  • @HenkHolterman 我刚刚发布了一个更新,因为这是我的解决方案,但是虽然我昨天确实遇到了锁定问题,但我通过将加密功能更改为异步解决了这些问题,从而解决了问题。如果 .wait() 不理想,还有其他首选解决方案吗?我将尝试重新引入 async void 并看看会发生什么,但如果您有其他解决方案,如果您能分享它,我将不胜感激。谢谢。
  • @HenkHolterman 我刚刚尝试过,但我又回到了原点。抛出错误,被吞噬,我的代码继续,然后抛出其他错误,然后捕获我的“UnhandledException”事件,但现在这是我想要的行为。我还在其他 2 台设备(即电话和 sp3)上尝试了 .Wait(),它似乎按预期工作。
  • @HenkHolterman,对不起,你是对的!它在Debug 模式下运行良好,但第二次我进入Release 模式并在我的手机上尝试它时,我的应用程序就挂了!!呜呜!!为什么不一致??
  • @HenkHolterman 我做到了,它捕捉到了错误,但这在我的 PCL 库中被捕捉到了,但我需要将它返回给我的应用程序。好吧,它正在被返回,但它被捕获在“App_UnhandledException”中,而不是在我的应用程序中创建 PCL lib 对象的“try/catch”中。这有意义吗?

标签: c# win-universal-app uwp


【解决方案1】:

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

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

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


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

【讨论】:

  • 我不确定我明白你在说什么。我在我的问题中添加了更多信息,因为它可能有点模糊。也许这会有所帮助,您也许可以更具体地告诉我应该在哪里处理这个问题?
  • 感谢您在此处提供更多信息。一旦我完成工作并尝试提供帮助,我将完成它。
  • 谢谢丹尼尔,非常感谢!
  • 我会推迟 Daniel,因为我认为 Henk 关于这个问题是重复的可能是正确的。请参阅我对 Henk 的回复。谢谢。
  • 没问题Thierry,希望你能解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-28
  • 1970-01-01
相关资源
最近更新 更多