Sdílet prostřednictvím


Be careful when making DataTransferManager.DataRequested an async function

Hello everyone,

Update: Thanks to Nigel Sampson for correcting my post. :)

As you probably already know, .NET Framework 4.5 introduced two new keywords: async and await. (Look here for information about how to use them.)

If you are adding the possibility to share content of your Windows Store application, you will have to implement the DataTransferManager.DataRequested callback. From the MSDN documentation:

This event is fired when a sharing operation starts—typically when the user taps the Share charm, although it is also fired if your app starts a share operation programmatically.

As with the callbacks on the App class (OnLaunched, OnActivated etc.), you can just convert this function into an asynchronous one. However, take the following sample implementation:

 async void App_DataRequested(DataTransferManager sender, DataRequestedEventArgs args) {     DataRequest req = args.Request;     await Task.Delay(500);     req.Data.Properties.Title = "Test";     req.Data.SetText("Hello World!");     req.GetDeferral().Complete(); }

 

If you use this code, when you are sharing data from your application, you will get a message like one of the following:

imageimage

 

“What happened?”, you may ask. Well, there is a trick to making this callback asynchronous.

If we think about the consequences of using async and await, and about the nature of the share operation, we can explain this behavior easily: Once the call to DataRequested returns, it expects the DataRequest to contain the information we want to share. However, if our callback is marked with async and we add a call using await, it will cause the execution flow to leave the function until we are notified by the awaiter that we can continue. DataTransferManager, however, does not know about this and will assume that we have completed the request correctly.

Fortunately, there is a way to tell DataTransferManager to wait for us: using the GetReferral method. Before, we only called it at the end of our callback, to mark the DataRequest as complete. However, if we call it at the beginning we will be able to call asynchronous methods:

 async void App_DataRequested(DataTransferManager sender, DataRequestedEventArgs args) {     DataRequest req = args.Request;     DataRequestDeferral deferral = req.GetDeferral();     await Task.Delay(500);     req.Data.Properties.Title = "Test";     req.Data.SetText("Hello World!");     deferral.Complete(); }

 

Please note that if the asynchronous operations will take more than 200ms you have to use a DataProviderHandler to prevent the operation from timing out.

I hope this helps you.

Cheers,

Helge Mahrt

Comments

  • Anonymous
    November 21, 2012
    This isn't entirely correct, the DataTransferManager has support for async share operations through it's deferral mechanism. In fact most of the event based things in Windows 8 do. The code works like the following. private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)        {            var deferral = args.Request.GetDeferral();            await Task.Delay(500);            args.Request.Data.SetText("Hello World");            deferral.Complete();        }