Reputation: 49590
I'm trying to save app data when the app is closing/deactivating. In WP8 I used StorageFile, which only supports Async methods.
The problem is (as I suspected and confirmed when reading this article), simply stated, that the OS lifecycle events and async methods don't mix well together. So, this does not work (even without async/await)
private async void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
var dataSvc = SimpleIoc.Default.GetInstance<ICachedDataService>();
await dataSvc.StoreCachedDataAsync();
}
The article suggests 2 workaround, neither one seems ideal:
My problem with (2) is that it still doesn't guarantee that it would have time to save even if I initiate it as soon as possible.
My problem with (1) is... beh... I'm using a ServiceLocator/IoC pattern (I could never remember which pattern is what), so this forces me to introduce synchronous operations in the interface of ICachedDataProvider
, for example.
Is there any other approach? Is it possible to convert an Async method into a synchronous method to increase code reuse?
Upvotes: 2
Views: 1115
Reputation: 1291
and thanks for the citation. As you found, there is the option of wrapping / kicking off the task and trying to synchronously wait for its completion.
But...this is a stopgap, at best. Once a close or deactivation operation is initiated, there is nothing that can stop it from happening, and nothing can defeat the "death clock" that gets started. Period. It is worth noting that the same applies to Suspensions in Windows Store apps. There is no mechanism to "buy more time" - Windows Store Apps do offer "deferalls", but as I mentioned in the post, those still operate within the constraint of the afore-mentioned "death clock."
I bring this up because you mentioned:
My problem with (2) is that it still doesn't guarantee that it would have time to save even if I initiate it as soon as possible.
As I read the concern, perhaps it is indicating a scenario where the app starts a "save as you go" operation, and then while the save is running, a lifetime event (close/deactivate) occurs...these lifetime events will be blissfully ignorant of the ongoing save and the app will ceded its execution and things will simply grind to an un-polite halt. In such a scenario, the save operation could include a synchronization flag to indicate that the operation is in progress, which could then be watched for inside of the lifetime event, but (at the risk of beating a dead horse) you still need to be aware of the whole "death clock" thing (plus things are starting to get complex/convoluted.)
Ultimately, if your app finds itself in a situation where a save may take longer than the allowable time, it may be important to rethink the exact mechanics at play and see if there's some way to avoid that situation in the first place. Although there are many ways to "play around" with asynchrony inside of this expiration time, expiration will happen.
Upvotes: 0
Reputation: 49590
I found something that seems to work, but I'm going to let this question sit for a while to wait for feedback or other solutions.
I modified the Application_Closing and Application_Deactivated to the following (based on this SO question)
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
var dataSvc = SimpleIoc.Default.GetInstance<ICachedDataService>();
var task = Task.Run(async () => { await dataSvc.StoreCachedDataAsync(); });
task.Wait();
}
Upvotes: 1
Reputation: 456587
Is it possible to convert an Async method into a synchronous method to increase code reuse?
Unfortunately, no. There are various approaches you can take to wrapping those methods, but none of them are foolproof. This blog entry describes the various approaches. In your case, I would recommend offloading to another thread; it's the easiest to get working, but would only work if ICachedDataProvider
is threadsafe.
Upvotes: 2