29 August, 2011

WP7.5 Mango–Isolated Storage Explorer

One of the most useful new tools with the latest Windows Phone SDK is the Isolated Storage Explorer.

It is a command line tool used for downloading and uploading the contents of an application’s Isolated Storage folders to either the Emulator or a Device.

There are two times when this is invaluable.

The first is when you are deploying a new version and you do not want to lose the data. Since day one I have been annoyed with the frequency that that deployment mechanism decides to delete the application and reinstall it. By using this tool I never need to worry about that again as I can just save a snapshot, deploy, load the snapshot back in.

The second is when I find a bug with while using a retail copy of my app which I can not hook the debugger into. I can take a snapshot, load it into the emulator and debug.

To speed the process along I have created four windows .bat files that to perform each of the tasks I need.

To use these yourself you will need to adjust the path if you are not on a 64bit system, and you will need to replace the GUID with the value from your WMAppManifest file.

24 August, 2011

Two lessons from a frustrating Mango submission

I thought I would share two quick lessons today. Learnt while submitting the latest gReadie update to the marketplace.

Lesson 1

When updating an application in the marketplace, you can not remove supported languages.

gReadie v1 has been translated into French and German (and unofficially Chinese) by enthusiastic users. gReadie v2 however has not yet had the same treatment.

Even though gReadie v2 is a whole new application (File | New Project) it is being submitted as an update to gReadie v1 so that all current licenses are maintained.

Therefore it must adhere to the rules for updates. One of which, I learnt today, is that you can not remove a language.

With apologies to my French and German users, I had to rush together a mix of human translated (where I had the same text in v1) and Google translated values to get the app into the marketplace. I will do my best to reach out to the original translators and see if they are willing to provide an update for me.

So keep this in mind if you are considering localising you application, you will need to do the same for all future versions.

Lesson 2

Be very careful what code is referenced by your Background Agent.

There are a whole range of APIs that Background Agents can not access, and the code detection for this is fairly blunt. If you reference a class in a class library which has another class that calls the prohibited APIs, your application will fail during submission.

To provide a more concrete example. gReadie is comprised of many separate class libraries. The two that caused me trouble were Quids.Infrastructure and gReadie.Library.

Quids.Infrastructure is a bunch of helpers classes (for example code to string HTML tags from text) and some basic ViewModel and ViewPage classes that form the basis of the MVVM implementation used in gReadie.

Even though my Background Agent just called into the string Extension Method that strips the HTML tags, the code that creates a PhoneApplicationPage was visible both in the ViewPage class and in the Silverlight Toolkit.

gReadie.Library servers a similar role but more specific to gReadie, it has all the Google API interactions, User Settings and a bunch of other similar code. Included is the code that creates Live Tiles and the code that handles the ProgressIndicator and SystemTray. All of which is prohibited in Background Agents. So even though my agent was just getting at the API and Settings classes, all classes were interrogated and submission failed.

So if you are building a Background Agent, and you want to share code between it and your main application be very careful about what else is in the shared libraries and be prepared to make UI and Non-UI shared libraries to deal with it.

19 August, 2011

Wp7.5 Mango–Background Agents

Late last year when I implemented the unread count Live Tile in gReadie I found myself stunned at just how complicated it was. It seemed to me that it would make a lot more sense if I could just whack a [LiveTileUpdater] attribute on a static method in a class and the phone would run that method occasionally.

I was therefore delighted when details about Mango were released as this is basically what Microsoft implemented.

Background Agents in Mango take the form of a separate assembly, which gets linked in your WMAppManifest.xml

You should also place a reference to this library in your main app just to make sure the compiler includes it in your .xap file.

You Background Agent library should contain a class based on ScheduledTaskAgent which performs the actual tasks.

There are two types of Background Agents, PeriodicTask and ResourceIntensiveTask. Your app is allowed one of each.

Full details are available here, but the important parts are that PeriodicTasks run around every 30minutes and can only run for 15 seconds before being killed. ResourceIntensiveTasks run when the phone is plugged in, on wi-fi and charged to over 90% battery, they can run for 10 minutes.

Finally your task should call either NotifyComplete() or Abort() when it is finished. Abort() will unschedule the task until your app runs again, so you only call it if something is wrong that needs user attention, such as login credentials changing.

Now that is the good part of the story, there is one more restriction on Background Agents. They are only allowed 5MB of memory, regardless of whether they are Periodic or ResourceIntensive. If you go over this limit the task will be killed.

Making a useful Background Agent that stays under these limits is incredibly difficult. Especially when so many of the basic framework components (HttPWebRequest, LINQ-to-SQL, IsolatedStorageSettings) appear to have memory leaks.

From my testing you will lose about half your memory by the time you reach line 1. Your first HttpWebRequest will eat up another roughly 20%, which it never gives back, though multiple requests will stay inside that initial chunk. IsolatedStorageSettings will do a similar thing.

LINQ-to-SQL is a little more complex, recycling your DataContext and Compiled Queries will give some back, but recycling them too often will leak as well. So you need to find a nice balance.

I suggest writing some code to monitor the memory usage between each job (assuming you have multiple to perform, say downloading multiple RSS feeds like gReadie does) and if you stray too high, then perform a garbage collection and recycle your LINQ-to-SQL and see how much you can get back. If it is not enough, then NotifyComplete() and try exit gracefully. It is not bullet-proof but in my testing it allows me to get more work done before running out of memory.

17 August, 2011

WP7.5 Mango–Compiled Queries

Over the last few weeks I have been doing a complete rewrite of gReadie, my Google Reader client for Windows Phone 7.

The original codebase for gReadie was really quite cluttered, and I wasn’t going to be able to take advantage of the new features Mango enables without pulling it all out and starting again.

With most of the rewrite behind me now, It is time to start putting together a few blog posts discussing the new features I am using and lessons learnt along the way.

One of the features I was most looking forward to in the 7.5 release of the phone is developer access to the underling SQL CE database. Access is provided through LINQ-to-SQL, which I have covered in detail previously. What I want to focus on today is improving the performance of your queries by compiling them and caching that result.

This post assumes you already have your DataContext created and working queries, if you do not, then please start by reading some of the Microsoft tutorials.

When you make a query with LINQ-to-SQL, the LINQ provider has to examine your LINQ expression and turn it into SQL, this process is done on every query. However, if you have a query you know you are going to call multiple times then you can run this process once, saving a parameterized result and avoid having to do this step on subsequent calls.

You define and call a Compiled Query like so

The first step is to define a delegate that at the very least takes an instance of your DataContext as a parameter (though you can define more) and also defines the result type.

You then use the CompiledQuery.Compile() method to provide the body for this delegate. The compilation does not happen until your first call, so don’t worry about setting up a lot of these.

One thing to note is that you can only re-run a compiled query against the same DataContext instance it was compiled against. So you need to ensure they have the same lifespan, and that you are not needlessly recreating your DataContext if you want to run multiple queries.

From my experience with Background Agents this method also uses less memory than rerunning the compilation each call.

One final code snippet to show an example with a parameter