Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WinRT, Javascript and the random "Access denied" exception

Some background

During last days I've been developing some Windows 8 HTML5/WinJS application. This application does some job using a WinRT component.

The JavaScript part starts an asynchronous operation in collaboration with the whole WinRT component: the callback function is given by JavaScript and the WinRT calls it when it has some asynchronous result.

I forgot to mention that the whole Windows 8 application isn't developed using the single page approach.

Problem

If the whole asynchronous operation is called in some page and you don't navigate to other pages, everything works as expected.

But, what happens when you navigate to other page? When the WinRT component needs to notify the JavaScript part about the result of the asynchronous operation: ACCESS DENIED EXCEPTION! And your application crashes.

What I've tried so far

  • The whole WinRT component method returns an IAsyncOperation<T>: before navigating to other page, I call the .cancel() method in JavaScript => NO LUCK
  • I've put the callback function into WinJS.Application.sessionState in order to be sure that the whole function isn't destroyed by the garbage collector => NO LUCK

The question...

Do I have any chance to notify the WinRT component to cancel it's asynhcronous operation and don't try to return the control to the JavaScript callback?

Thanks in advance

You can check that others have found the same problem before:

  • http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/5f9ebfe6-d652-442d-850d-41bda5e370c9
like image 956
Matías Fidemraizer Avatar asked Nov 03 '22 05:11

Matías Fidemraizer


1 Answers

I've found a solution after some trial-errors.

Answering to my own question:

Do I have any chance to notify the WinRT component to cancel it's asynhcronous operation and don't try to return the control to the JavaScript callback?

Yes, but not directly.

So, how?

  1. In the WinRT, C# component-side, design a CancellationTokenSource property in the C# WinRT component and, assign it just before the call to the asynchronous operation.
  2. Create an instance of CancellationTokenSource and set it to the property created in the previous step just before calling the asynchronous operation.
  3. Fluently-continue with ContinueWith method the asynchronous operation before converting the .NET Task into a WinRT IAsyncOperation<T> and give the CancellationToken created as part of the previously instantiated CancellationTokenSource to the ContinueWith method (see cancelling tasks: http://msdn.microsoft.com/en-us/library/dd997396.aspx).
  4. Implement a CancelCurrentAsyncOperation method in the WinRT component that will call CancellationTokenSource.Cancel().
  5. Call the previously CancelCurrentAsyncOperation method in WinJS/JavaScript before navigating to another page.

WinRT component sample code:

public sealed class MyWinRTComponent 
{
   private CancellationTokenSource { get; set; }

   public void CancelLastAsyncOperation() 
   {
       if(CancellationTokenSource != null) 
       {
           CancellationTokenSource.Cancel();
       }
   }

   public IAsyncOperation<string> DoSomethingAsync() 
   {
        CancellationTokenSource = new CancellationTokenSource();

        return DoSomethingAsync()
                     .ContinueWith<string>(task => task.Result, CancellationTokenSource);
   }
}

JavaScript sample code:

var component = new MyWinRTComponent();
component.doSomethingAsync().then(function(text) {
   // Do stuff
});

// Before navigating to other page
component.cancelCurrentAsyncOperation();

That worked for me!!

like image 107
Matías Fidemraizer Avatar answered Nov 15 '22 07:11

Matías Fidemraizer