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 classconstructor
?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.