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

4
我的UWP应用程序首先会检查是否有包含数据的文件可用。如果有,它将尝试解密这些数据并继续下一步,但如果加密文件已被篡改或损坏,则我正在尝试通过抛出错误显示相关信息的消息对话框。
尽管我对事件链的发生顺序和它们在相关位置上受到try/catch保护的情况非常确定,但它没有捕获事件链中的“更高级别”问题,最终跳到了。
private void CoreApplication_UnhandledErrorDetected(object sender,
UnhandledErrorDetectedEventArgs ex)

我不明白为什么“高级”的try/catch无法捕获此异常?

可能是因为:

  • 它来自于我在构造函数中调用的私有异步方法 private async void

  • 当我的DataService在ViewModelLocator中创建服务时生成,因为我使用了MVVMLight?

有没有办法从CoreApplication_UnhandledErrorDetected显示消息对话框?我已经研究了一段时间,但找不到解决方案。它会抛出错误,称不允许这样做。

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

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

更新-1:

我想提供更多细节/代码,因为问题仍未解决。

实际上,我正在使用IOC / DI加密/解密数据。加密类本身(EncryptionService)位于主应用程序中并实现接口(IEncryptionService)。

当第一次创建注入到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对象(基于IEncryptionService)并将其传递给MyExternalService类。
MyExternalService的构造函数中,它通过调用静态方法即Instance来创建MyPCL的单例对象,并将在DataService中创建并传递给MyExternalServiceEncryptionService对象传递给它。
正如您下面所看到的,在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,并且我有两个函数。Encrypt 和 Decrypt 都是异步调用。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!),我更改了从构造函数调用我的异步方法的方式。
我直接调用了ReadSetting而不是调用我的ReadSettingsData方法,该方法是一个虚拟的void方法,我可以从构造函数中调用ReadSettings。
public MyPCL(IEncryptionService encryptionService)
{
    this._encryptionService = encryptionService;
    ReadSettingsData().Wait();
}

注意 .Wait()。一旦完成,我终于能够捕获异常并将其推回到我的事件链中,一直返回到我的应用程序,并显示消息并采取适当的操作。
由于这是我们应用程序的关键错误,不应该发生,因此我确保引入了一个特定的异常,即EncryptionServiceException,并在ReadSettings中捕获并相应地抛出。
由于我没有在任何其他地方放置try/catch,它从MyExternalPcl库被推回到我的应用程序,但它不是常规异常,而是作为AggregateException返回,但可以按照本文处理: 如何: 处理任务引发的异常,以下是核心代码段:
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,我可以决定该怎么做。我明天会进行更多检查并确认,但无论如何,谢谢。 - Thierry
@HenkHolterman 我刚刚发布了一个更新,这是我的解决方案,昨天我遇到了锁定问题,但通过将我的加密函数更改为异步函数,我解决了这个问题。如果.wait()不是理想的解决方案,是否有其他首选解决方案?我将尝试重新引入异步void并查看结果,但如果您有其他解决方案,我会非常感激您能分享一下。谢谢。 - Thierry
@HenkHolterman,我刚试过了,但我回到了原点。出现错误,被吞没,我的代码继续执行,然后抛出其他错误,然后被“UnhandledException”事件捕获,但这是我想要的行为。我还在另外两个设备上尝试了等待(.Wait()),即手机和SP3,似乎按预期工作。 - Thierry
@HenkHolterman,抱歉,但你是对的!在Debug模式下它运行得很好,但当我切换到Release模式并在手机上尝试时,我的应用程序就会卡住!!真气人!!为什么会有这种不一致性?? - Thierry
@HenkHolterman 我已经这样做了,它可以捕获错误,但是这个错误被我的PCL库捕获了,但我需要将其返回到我的应用程序中。嗯,它正在被返回,但它被“App_UnhandledException”捕获,而不是我在应用程序中创建PCL lib对象的“try/catch”。这有意义吗? - Thierry
显示剩余3条评论
1个回答

1
作为Henk提到的,每个异步方法都应该处理自己的异常。
如果您想要显示来自异步方法抛出的异常信息,您应该在UI线程上调用消息对话框,如下所示:
async void showMessageDialogMethod()
    {
        MessageDialog dialog = new MessageDialog("Sample message");
        await dialog.ShowAsync();
    }


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

我不确定我理解你的意思。我已经在我的问题中添加了更多信息,因为它可能有点模糊。也许这会有所帮助,你可以更具体地告诉我应该在哪里处理这个问题? - Thierry
谢谢,现在这里有更多的信息。我下班后会仔细阅读并尝试提供帮助。 - Daniel Krzyczkowski
谢谢Daniel,非常感谢! - Thierry
我认为这个问题可能是重复的,建议等待一下,看看Henk的回答。请参考我对Henk的回复。谢谢。 - Thierry
没问题,Thierry。我希望你能解决这个问题。 - Daniel Krzyczkowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接