Creating a background task for a Windows 8 app

My first Windows 8 app has a "Live Tile". To update this live tile I have a background task. The scenario is as follows: My app "Irish Tides" pulls tide height and time prediction values back from a website. The user can chose between 130 different ports around the Irish coast. It gets values for the next 7 days for one port from each call. The live tile pane "queue" has a size of 5, so my app's live tile feature is to show today's high tide data for each of the 5 most recently queried ports. Eg. if today is the 13th December (which it is) and one of the last 5 ports you queried with the app was Baltimore (and as this is the Irish Tides app, that's the original; Baltimore, West Cork - not in Maryland), then one of the tiles panes you will see should be like this:

 

 

 

But tomorrow this should say "High Tides - Fri 14 Dec" and unless the user can be relied upon to launch the app every day and click on each of their favourite 5 ports, then we need a way to update this - a background task. As the user clicks on ports and causes tide/week data to be displayed in the app the 7 day data for each port is stored in a queue with a size of 5. So this queue has the data for the 5 most recently viewed ports, and then saving that queue persists this data for access when the app is not running. This gives the background task all the data it needs for 5 ports for 7 days at a time. So we get a local xml file in this format:

 

 <?xml version="1.0"?>
 <ROOT>
 <Port Title="Black Ball Harbour" ID="0732">
 <Day DayDate="Thu 6 Dec">
 <Tide Height="1.2 m" Time="03:18" HWLW="LW"/>
 <Tide Height="3.1 m" Time="09:30" HWLW="HW"/>
 <Tide Height="1.3 m" Time="15:56" HWLW="LW"/>
 <Tide Height="3.0 m" Time="21:56" HWLW="HW"/>
 </Day>
 <Day DayDate="Fri 7 Dec">
 <Tide Height="1.2 m" Time="04:23" HWLW="LW"/>
 <Tide Height="3.0 m" Time="10:33" HWLW="HW"/>
 <Tide Height="1.3 m" Time="16:56" HWLW="LW"/>
 <Tide Height="3.0 m" Time="22:58" HWLW="HW"/>
 </Day>
 <Day DayDate="Sat 8 Dec">
 <Tide Height="1.2 m" Time="05:22" HWLW="LW"/>
 <Tide Height="3.0 m" Time="11:30" HWLW="HW"/>
 <Tide Height="1.2 m" Time="17:57" HWLW="LW"/>
 <Tide Height="3.0 m" Time="23:58" HWLW="HW"/>
 </Day>

 

 

Creating the background task

The background task then needs to:

 1. Run at least once a day

 2. For each port in the xml file, read the tide high water data for that day

 - and if that day's data is not available, make the call to the web server and update the xml file with the next 7 days data fior that port.

 3. Make a tile pane with the port name as the id (so it will overwrite yesterdays pane for that port) and push the pane to the tile queue.

  

Running at least once a day

 The background tasks needs a trigger that will fire at least once a day, and as I don't want to rely on being on the lock screen the number of trigger types I can use are limited. I started out using a maintenance tasks, firing every fifteen minutes. This was great during the dev phase as I could almost let the task to run "naturally" (without using the Debug\Resume menu to force it), so I could change stuff, take a break, come back and hopefully see tiles updated, nice. But don't want to run unneccessary tasks on my users machines every fifteen minutes - I had figured I'd just extend the trigger time to 2 or 3 hours for release, but then I thought that may mean the user could be logged in for 2 or 3 hours with yesterday's data in the live tile, not an optimum experience.

 

So just before releasing (and I'm carefully watching my friends installs to prove this works (fine since Monday, fingers crossed) I changed the tigger to be "SystemTriggerType.InternetAvailable". The idea being that the user probably only logs in 2 or 3 times a day and on at least one of those occasions the internet will be available - it will be required anyways if the task needs to contact the server for a new 7 day data set. So the task registration code is:

 

 

  SystemTrigger taskTrigger = new SystemTrigger(SystemTriggerType.InternetAvailable, false);
 
 string entryPoint = "Tasks.BackgroundTileUpdate";
 string taskName = "Irish Tides Background Tile Updater";
 
 BackgroundTaskRegistration task = RegisterBackgroundTask(entryPoint, taskName, taskTrigger, null);
 
 
 public static BackgroundTaskRegistration RegisterBackgroundTask(string taskEntryPoint,
 string taskName, IBackgroundTrigger trigger, IBackgroundCondition condition)
 {
 foreach (var cur in BackgroundTaskRegistration.AllTasks)
 {
 if (cur.Value.Name == taskName)
 {
 return (BackgroundTaskRegistration)(cur.Value);
 }
 }

But only running once a day (at most)

I still don't want to be running anything anymore than is absolutely necessary, so the background task Run method calls the Tile update method, but only if this task has not been run previously today. I accomplished this as follows - simply saving todays day number locally (31st Dec is day number 365 on non-leap years). Obviously I need to cover the case where this has not been run before and there is no local day number saved. I did it as follows - open to comments or improvement suggestions.

 

  public async void Run(IBackgroundTaskInstance taskInstance)
 {
 BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
 taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
 _taskInstance = taskInstance;
 
 Debug.WriteLine("BackgroundTask running");
 
 //if Tile was not updated today, update it now
 if (!SameDay())
 {
 await UpdateTiles();
 }
 _deferral.Complete();
 }
 
 private bool SameDay()
 {
 var key = string.Format("{0} Last Run Day",_taskInstance.Task.Name); 
 
 var settings = ApplicationData.Current.LocalSettings;
 int lastRunDay = 0;
 
 if (settings.Values.ContainsKey(key))
 {
 lastRunDay = (int)settings.Values[key];
 }
 else
 {
 lastRunDay = 0;
 }
 
 settings.Values[key] = DateTime.Now.DayOfYear;
 
 if (lastRunDay == DateTime.Today.DayOfYear)
 {
 return true;
 }
 
 return false;
 }

 

 

Project architecture

In the end I finished up with three projects in the solution.

PortsDaysTides

- has all the "utility" classes and methods for making calls to the webserver, saving files, deseriliazing port data etc...

W8Tides

 - is the Win8 app, containds the mainpage.xaml.cs and a few others (About page etc...)

Tasks

 - the background tasks solution.

 

Gotchas - 1

The Live tile and background task part of this project was a challenge. I hadn't done it before and the concept of the background project took me a little while to get used to. Initially, although I had run the samples without error, I could not get my own background tasks to fire. The error in the event log mentioned something about capabilities not being declared. It took me a short while to realise that you need to pay attention to a few details when setting up background tasks.

 

Basically to make this work you need to make sure of a few little things; the type of things which unobservant types like me can sometimes miss.

 

My Task is called BackgroundTileUpdate in the Tasks namespace.

The package App manifest needs to have the:

- Background task capability set

- The correct property set for the trigger type used.

- The Entry point set to match your namespace and class name.

 

 

Gotchas - 2

Your background tasks project must be referenced in your Windows 8 store app project.

 

If I rememember these gotchas next time I think I'll be fine!