Tuesday, December 11, 2012

Using TimeTrigger in Windows Store Apps

Using push notfications is all good and great, but many times you do not have resources to do so and just want some simple code to run from time to time to update your app's status. In my case, a pending document count.

For this purpose, you can create background tasks and add a TimeTrigger that can be executed as often as every 15 minutes.

Basically, you register your task like so:

// find out if task is already running

var existingTask = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault(
      t => t.Name.Equals(
      Constants.TILE_UPDATER_TASK_NAME,
      StringComparison.CurrentCultureIgnoreCase));

if (existingTask != null)
   return;    

// no task exists, create and register task
var taskBuilder = new BackgroundTaskBuilder
                  {
                     Name = Constants.TILE_UPDATER_TASK_NAME,
                     TaskEntryPoint =   
                     typeof(ReadSoft.Online.Approve.BackgroundTasks.TileUpdater).FullName
                   };

// specify when to invoke: every n minutes, when internet is present
taskBuilder.SetTrigger(new TimeTrigger(15 , false));
taskBuilder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
           
// register
var updaterTask = taskBuilder.Register();

Need more info? Read Registering a background task and Run background task on a timer


"Ok, great, but it's not working. Now what?"
Reading the links above, it's stated that in order for any background task to run, you need to also specify the class in the app manifest.



"Ok, great, but it's not working. Now what?"
Also stated in the MS documentation is that in order for a TimeTrigger to work, your app needs to be on the lock screen. You can request this on startup by calling RequestAccessAsync on the BackgroundExecutionManager. Note the try catch since you might have problems in the simulator with this (as did I), like so:

private async void RequestLockScreenAccess()
{
  try
  {
    var status = await BackgroundExecutionManager.RequestAccessAsync();
   }
   catch (Exception)
   {
   }
}

You can ofcourse handle the result (the user might say No) how you would like to, perhaps show a nagging screen explaining how important for the world peace it is that your app is on the freakin lock screen. Would someone pleeease think of the children!!  :)


"Ok, great, but it's not working. Now what?"
Not very visible in the documentation (it is mentioned in a white paper, but I actually got the info from a MS evangelist) is that your background class needs to be in a separate WinMD project. Do the rightclicky thing and add a new project pronto! Don't forget to update your app manifest with the (full) name of the class inside the WinMD instead of the one in your app.

Ok, but you've got all that nice code that checks with your webservice for status that you are also using inside the app, could you just put all that code in the WinMD project and then reference that from your app? No can do. Putting service references stuff in a WinMD doesn't play well because of generated classes not being public and other annoying things.

You need to put your reusable code in yet another project, but just a normal class library this time. Then, reference that lib from both your WinMD project and your app project and boom you're done.


"Ok, great, but it's not working. Now what?"
Running in the simulator? Try a real device instead.

OperationContextScope and async/await

So, we're doing a Windows 8 app. Yay :)
Being a c# and Silverlight kinda guy, the time needed to get up and running was incredibly small. As always, Microsoft are very good on the Tool-side of things and the "F5" experience works very well in the Windows 8 area.

Our services are WCF based, and we support both REST and SOAP.
In this case, we decided to use the SOAP way since our REST client helper library did not exist for Win8.
"Add New Service Reference" and boom we got ourselves some client code.

To make this work though, we had to put some time into the connectivity/authorization part.
We use a cookie to store authentication token (you know, standard ASP.NET authorization) and we needed  to pass along that cookie with other calls. We found that the best way to do so was to use the OperationContextScope and a previously saved cookiecontainer from the authorization call.


// prepares a soap client with the stored cookie container
var docClient = CreateDocumentServiceClient();

// call webservice
using (new OperationContextScope(docClient.InnerChannel))
{
   var doc = docClient.GetDocumentAsync(docId);
}


(...not gonna go into details of how to store a cookiecontainer etc, but I'm sure your friend Google could aid you if needed.)

In many of our calls, we needed to check something after the async call, so we started using await


private async void DoStuffWithDoc()
{
  var docClient = CreateDocumentServiceClient();  
  using (new OperationContextScope(docClient.InnerChannel))
  {
     await var doc = docClient.GetDocumentAsync(docId);
     if (doc.YadaYada)
     {
          // more code here
     }
  }
}


This mostly worked fine, but after a while we started noticing Exceptions, especially when doing other things in parallel. Often, it was "This OperationContextScope is being disposed on a different thread than it was created". When looking at the documentation for OperationContextScope it states that:
Caution noteCaution
Do not use the asynchronous “await” pattern within a OperationContextScope block. When the continuation occurs, it may run on a different thread and OperationContextScope is thread specific. If you need to call “await” for an async call, use it outside of the OperationContextScope block


Aha! So, how do you solve this?
The await keyword will split up your code and basically create a new method of all the code after the await keyword (and that "new method" will be executed in a separate thread sometimes). Because the end of the using statement is after the await keyword, the Dispose of the OperationContextScope instance will take place in the "new method" that might run in a separate thread.

The solution is very easy, just make sure you do not use await inside a OperationContextScope. Duh!

So, all of our methods doing any kind of webservice call with an OperationContextScope needed to be refactored looking something like this:


private async void DoStuffWithDoc(string docId)
{
   var doc = await GetDocumentAsync(docId);
   if (doc.YadaYada)
   {
        // more code here
   }
}

public Task<Document> GetDocumentAsync(string docId)
{
  var docClient = CreateDocumentServiceClient();
  using (new OperationContextScope(docClient.InnerChannel))
  {
    return docClient.GetDocumentAsync(docId);
  }
}


See what we did there?
The await keyword has been moved outside the OperationContextScope to the calling method instead, and we immediately return after the call using the OperationContextScope.

Problem solved!

Thursday, January 26, 2012

Silverlight 5 Tools installation issue



We recently updated our grand solution to Silverlight 5. My neighbour colleague was responsible for the upgrade, and he got through it without any major hickups.

So, now all I needed to do was to refresh my workspace code, update my machine to Silverlight 5 tools and fly off to the no-compilation-error heaven.

"Not so fast there pretty boy", Microsoft's Silverlight 5 Tools installer quickly told me.
Well, actually, the exact words were: "Setup has detected that Visual Studio 2010 Service Pack 1 is not installed, which is required to install the following product", but you get the point.

So, just install the SP1 already right? Problem is, it was already installed, and had been so for the last 6 months or so. My setup was:
- Visual Studio 2010 Premium, with SP1 applied
- Windows 7 Enterprise
- Beefy 64-bit system with Intel i7 cpu and 12 gigs of sweet sweet RAM.

I tried everything, up to the point where I uninstalled the SP1 and reapplied it. Still same error. Darn.

After two days of digging, I found this post where someone had a similar error with the RC version. Apparently, the tools-setup is just a selfextracting zip which can be unpacked. Great, so I could unpack this thing, skip the stupid installation wrapper and install the parts individually. (parts = dev runtime, VS tools, RIA services)

Or so I thought. Turns out, the wrapper installation actually did something as well besides just kicking of other setup packages because although I could now install the parts, the VS solution couldn't load.

So, I needed a way to run the entire installation, but just skip the small part where it checks (incorrectly) for VS 2010 SP1. The answer lays in the magic file called ParameterInfo.xml

This file (inside the zipped package) determines what to check before running the installation. It's a simple to read and understand xml file, so I could easily pinpoint the xml-elements that tried to check for SP1, remove them, and then run the installation package as a whole (still unpacked though).

Success!

Thnx MSFT, I'll be sending you guys an invoice at the end of this month charging the hours I needed to spend on this.

/ jon