4

The first action my UWP app takes is check if a file that contains data is available. If it is, it will try to decrypt this data and go on to the next step but I'm trying to display a message dialog with the relevant information if the encrypted file has been tempered with or is corrupted by throwing an error.

Even thought I'm 100% sure of the chain of event occurring and that they are protected by try/catch in the relevant places, it's not catching the "higher" ones in the chain of events and it eventually jumps to

private void CoreApplication_UnhandledErrorDetected(object sender,
UnhandledErrorDetectedEventArgs ex)

I don't understand why "higher" try/catch is not catching this exception?

Could it because:

  • it's coming from private async void method called from my class constructor?

  • it's generated when my DataService is being created in my ViewModelLocator where it's creating the services as i'm using MVVMLight?

Is there anyway to display a message dialog from CoreApplication_UnhandledErrorDetected? I've been researching it for a while now and can't find a solution as how I can do this. It's throwing an error saying that this is not allowed.

I've also added the UnhandledException event but that's not being triggered.

What's the best way to handle an exception that being thrown when an application starts?

Update-1:

I thought I'd provide more details/code as it is still not sorted.

I'm actually using IOC/DI to encrypt/decrypt data. The encryption class itself (EncryptionService) is in the main app and implements an interface (IEncryptionService).

An EncryptionService object is created when my DataService class is created the first time when it is injected in AppShellViewModel's constructor:

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

As you can see, when the IDataService is injected into my AppShellViewModel's class, it creates the DataService class which in turn will create my new EncryptionService ojbect (based on IEncryptionService) and pass it to MyExternalService class.

In the constructor of MyExternalService, it creates a singleton object of MyPCL by calling a static method i.e. Instance and passes the EncryptionService object that was created in the DataService and passed on to MyExternalService.

As you can see below, I read my settings in the constructor of MyPCL. This is happening once the singleton object has been created. It reads the settings and then try to decrypt the data using the EncryptionService object that was passed from my app and is implements the 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);
     }
   }
}

Now in my main app, the EncryptionService uses Windows.Security.Cryptography.DataProtection and I've got 2 functions in it. Encrypt and Decrypt which are making async calls. The Decrypt function is defined as follows:

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

Ok, I think that the above, while simplified, represents the gist of it.

When it tried to decrypt the tempered data by calling:

IBuffer decryptedBuffer = await provider.UnprotectAsync(data);

It is where it throws the error which is fine but how to I catch it and display that something went wrong and take a specific action??

I've removed all error handlers for now and I hoping one of you will tell me where exactly I need to put it as pretty much every functions in DataService, MyExternalPcl and MyPCL had error handling and it still bombed out and went to CoreApplication_UnhandledErrorDetected

Thanks.

UPDATE-2:

Ok, it required quite a bit of messing around to eventually find out the right way to handle this, but Henk did put me in the right direction.

My first problem, unlike what was described in my question, I was using the synchronous function for Protect and Unprotect. The same applied to my Encrypt/Decrypt function. I changed them both to use the async functions of Protect and Unprotect and modified both Decrypt and Encrypt to DecryptAsync/EncryptAsync and made sure they were returning Task.

It may sound like a small thing, but this had to be fixed or it caused my app to lock/hang.

The next part I changed based on what was suggested in this post Catch an exception thrown by an async method, (Thank you Henk!) was how my async method was called from the constructor.

Instead of calling my ReadSettingsData method which was a dummy void method introduced so that I could call ReadSettings from my constructor, I called ReadSetting directly but as follows:

public MyPCL(IEncryptionService encryptionService)
{
    this._encryptionService = encryptionService;
    ReadSettingsData().Wait();
}

Notice the .Wait(). Once done, I was finally able to catch the exception and push it back my chain of event, all the way back to my app and display an a message and take appropriate action.

As this is a critical error for our app and should never occur I made sure to introduce a specific exception i.e. EncryptionServiceException and it is being caught in the ReadSettings and being thrown back accordingly.

As I didn't put any try/catch anywhere else, it is being pushed back to my app from MyExternalPcl library but instead of being a regular exception it is returned as an AggregateException but this can easily be handled as per this article: How to: Handle Exceptions Thrown by Tasks but here's the core snippet:

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

}

Hope this helps.

Community
  • 1
  • 1
Thierry
  • 6,142
  • 13
  • 66
  • 117
  • @HenkHolterman I think you might be right. I've added .Wait() and it has definitely improved things. I now generates an aggregate exception which I can handle and now my UnhandledException is also being triggered and I can decide what to do. I'll do more checks tomorrow and confirm but I think you might be right anyway. Thanks. – Thierry May 25 '16 at 16:51
  • @HenkHolterman I've just posted an update as this being my solution but while I did get locking issues yesterday, I resolved them by changing my crypto function to async and that solved the problem. if .wait() is not ideal, is there another preferred solution? I'll try to re-introduce the async void and see what happens but if you have another solution, I'd really appreciate if you could share it. Thanks. – Thierry May 26 '16 at 10:26
  • @HenkHolterman I've just tried it, but I'm back to square one. Error is thrown, being swallowed up and my code continues and then throws other error which are then caught my 'UnhandledException' event but this is now the behaviour I want. I've also tried .Wait() on 2 other devices i.e. phone & sp3 and it seems to work as expected. – Thierry May 26 '16 at 10:33
  • @HenkHolterman, sorry but you were right! It works great in `Debug` mode but the second I went to `Release` mode and try it on my phone, my app just hangs!! Grrr!! Why the inconsistencies?? – Thierry May 26 '16 at 12:17
  • @HenkHolterman I did and it catches the error as far as that but this is caught in my PCL library but I need to return it back to my app. Well, it is being returned but it is being caught in 'App_UnhandledException' instead of the "try/catch" that I have where the PCL lib object is being created in my app. is that making sense? – Thierry May 26 '16 at 15:03
  • @HenkHolterman The problem is that this is being called from my PCL class constructor when the static method Instance is called from my app and create the actual instance of this class. – Thierry May 26 '16 at 16:26
  • Do read http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html – H H May 26 '16 at 17:37
  • @HenkHolterman - I understand. Not easy to explain when you can't provide the full picture. Regarding, UnprotectAsync, it is a function from `Windows.Security.Cryptography.DataProtection`. The reason I have file.ReadAllTextAsync().Result is that I needed the operation to be synchronous. I'll have a look at it again and try to use Task instead but I remember having problems as it wouldn't wait for the operation to be completed and therefore gave me grief as the code continue without having the data. Thanks again for your help and I'll have a read at the article you provided. Take care. – Thierry May 27 '16 at 19:43

1 Answers1

1

As Henk mention every async method should handle its own exceptions.

If you would like to display some information from async method about thrown exception you should invoke message dialog on the UI thread like below:

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


await Dispatcher.RunAsync(CoreDispatcherPriority.High,
                       () => showMessageDialogMethod());
Daniel Krzyczkowski
  • 2,732
  • 2
  • 20
  • 30