All posts by Jon

Web API, JSON by Default in Web Browsers

I use a few methods for examining and debugging JSON output. One of those is to view it in a browser. If that browser is Internet Explorer, then the file just gets opened automatically in Notepad++ (which, nicely, will also just keep updating an existing file, avoiding tab clutter). There, I use the JSON Viewer plugin, which is decent enough, if a bit unpolished. If the browser is Chrome, I use JSONView. One advantage is that if the JSON doesn’t end up formatted, you know right away it isn’t valid. But, unlike JSONLint it can’t tell you where the problem is.

For whatever inane reason (XML is dead, right? :-)) Chrome likes to tell servers that it accepts XML. So your “purist” Web API that is set up to deliver only JSON gets this request and fails to serialize into XML. So Chrome just gets a big, nasty error message back.

Fortunately, there is way to head this off at the pass. In the Web API global.asax.cs file you can remove the XML formatter (if you’re never going to use it):

using System;
using System.Linq;
using System.Web;
using System.Web.Http;

namespace GeoDataAPI
    public class Global : HttpApplication
        protected void Application_Start(object sender, EventArgs e)

            // Ignores browsers like Chrome requesting xml.
            var config = GlobalConfiguration.Configuration;
            var appXmlType =
                config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");

Another approach is to use

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

But I found this caused a problem with third-party data that contained HTML break tags. The JSON was sent out with carriage returns, which caused it to be invalid. If you don’t need XML, I recommend the other way of doing this.

Working with JSON and C#–for Lazy Programmers

It just so happens that only a day ago I embarked on using Nokia’s HERE Places API in a new app. Then this morning saw a tweet by Lance McCarthy:

And, after checking out, realized I was much better off using its generated classes than what I had been doing, which was just grabbing what I needed into a relatively barebones class using a dynamic object.

Dynamics are great. But in this case, it’s so much better using the generated class. If it wasn’t for the json2csharp converter I wouldn’t bother because I don’t need all that is spewed out by the Places API…and it is verbose. But just getting Intellisense alone makes it pure gold. (Shout out to Lance and to Jonathan Keith, the creator/maintainer of the site).

Let’s look at some code comparisons. Creating a new object using the class is a bit more verbose, but certainly no more complicated:

var placeInfo = await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<HerePlaceInfo>(responseStr), cancellationToken);


dynamic dynObject = await Task.Factory.StartNew(() => JObject.Parse(responseStr), cancellationToken);

But from then on it gets much nicer working with it:

var oTitle = placeInfo.related.publicTransport.href;


var dTitle = dynObject.related["public-transport"].href.Value;

The former provides Intellisense all the way (very useful for delving into nested JSON schemas) as well as a less complicated, shorter syntax.

You may have noticed in this particular example the “public-transport” key has a hyphen. That is something I wish the authors of the HERE Places API hadn’t done. The Json2Csharp converter flagged this since it couldn’t create a proper camelCase name. Even if it had, that wouldn’t do any good because it wouldn’t automatically match incoming JSON, leaving us with a null value.

To get around this, you can give the item a legal name and decorate it:

[JsonProperty(PropertyName = "public-transport")]
public PublicTransport publicTransport { get; set; }

You don’t have to do anything to the class that it references, e.g:

public class PublicTransport
public string title { get; set; }
public string href { get; set; }
public string type { get; set; }

Here’s another example, digging into the location data to mine the latitude and longitude:

var locationY = placeInfo.location.position[0];
var locationX = placeInfo.location.position[1];

var locPoint = new Point(locationX2, locationY2);


var locationY = (double) dynObject.location.position[0];
var locationX = (double) dynObject.location.position[1];

var locPoint = new Point(locationX, locationY);

And if you still aren’t convinced, consider that with a dynamic you can’t use LINQ (at least not easily…and I’ll leave that to others):

var categories2 = placeInfo.categories.Select(category => category.title).ToList();


var categories = new List<string>();

var catArray = dynObject.categories;

foreach (var category in catArray)

If the JSON2Csharp class seems verbose, keep in mind you can comment out or delete the parts you won’t need. That won’t prevent JSON.NET from populating the object instance.

Using Microsoft Live for Authentication with Windows 8.x and Windows Phone 8 Apps

If you’re the impatient type and are just looking for a code sample, check out I would also appreciate any comments or suggestions to make the code better. The solution contains a Web API service and Windows 8/Windows Phone apps.

I first started looking into this because I needed a way to authenticate users and didn’t want to build or maintain such a system. Additionally, people are used to being able to use social media accounts, which reduces resistance to trying out something new. For the time being, since my apps are for these two platforms I’ve chosen to focus on using just Live authentication. A good part of that is the user experience with more comprehensive approaches wasn’t very satisfactory. A significant design goal is to re-use as much code as possible across Windows 8 and Windows Phone.

Performing authentication and using to securely connect to a service involves some significant steps and pieces:

1)      Registering Client Apps and Services with the Windows Store and Microsoft Live

2)      Setting up a Service

3)      Assembling the right combination of code to authenticate properly and at the right times.

4)      Using the Live SDK and a JWT (JSON Web Token) decoding and verification library

Furthermore, there are certain design goals that need to be met:

1)      Avoid having user log in as much as possible…preferably only once.

2)      Maintain security, both locally and on the server

3)      Make the experience as seamless as can be

4)      Re-use as much code as possible across Windows 8 and Windows Phone

Like many things, it was overwhelming at first to see how the pieces of the puzzle fit together. This is complicated somewhat by differences in the way Windows 8 and Windows Phone handle signing in and staying signed in/authenticated. As you may know, Windows 8 operates on the principal of SSO (single sign on) with Microsoft accounts. Applications don’t have their own interface for signing in. All the user will see upon installing the application is a one-time pop-up asking for permission to use whatever scopes the app has requested. All you have to do is include wl.signin in your sign-in scopes.

 image001  image002
Windows 8 Windows Phone

Note: See below on how to reset this after you’ve tested it with an account

Windows Phone, on the other hand, doesn’t use SSO. Fortunately the Live SDK handles this as long as you, again, remember to include wl.offline_access. Then the only difference is that you have to sign in (via a browser pop-up in the app) to your Microsoft account one time.

Note: If you’ve looked at Live SDK samples for Windows Phone they include a sign-in button (or at least used to when I first investigated them). It’s not necessary to use. The code included in this post and in the accompanying download will demonstrate that.

So how does the authentication process work anyway?

It’s important to have an overview of the process. The application needs to be able to authenticate itself with the server. This is handled by communicating with Live (when necessary), which returns a JWT (JSON Web Token). The JWT is then passed to the server with every call (yes, that’s right) as an Authorization header. The server validates the JWT and if it passes returns the requested data.


At no time are user credentials or client secrets stored within the client. This is critical because no matter what steps you take to obfuscate code there’s no guarantee the app won’t be compromised.

What’s a JWT and what does it contain?

A JSON Web Token is a string containing three parts – a header, a claims section, and a signature. The first two are JSON strings, e.g  {“typ”:”JWT”,  “alg”:”HS256″}, which are base-64 encoded. The signature is hashed using – and this is important – the client secret Live generates for your app (more on this in a moment). It is also encoded, then all three parts are concatenated, separated with a period, such as:


This particular example would be decoded as:



    “alg”: “HS256”,

    “typ”: “JWT”




“urn:microsoft:appuri”: “appid://00000000XXXXXXXX”,

“urn:microsoft:appid”: “00000000XXXXXXXX”,

“uid”: “xyz123”,

“iss”: “urn:windows:liveid”,

“exp”: 1391106249,

“ver”: 1,

“typ”: “JWT”,

“aud”: “”


Signature (encoded)


The items that are important as far as server validation is concerned are the issuer and audience. Also of importance is the expiration UTC date/time, which is expressed in Unix epoch seconds. This is covered more in the Sample section.

One thing you should understand about JWTs is that they are not encrypted. Only the signature is. So if not debugging traffic, strongly consider using HTTPS. If you need to authenticate a user, whatever traffic you’re sending probably needs to be encrypted anyway.

Note: uid (user id) is a unique user id specific to the app (as registered with Live). In other words, the uid will be the same for both a Windows 8 app and a Windows Phone app using the same app registration. And it will be the same across multiple devices. Another id source, of course, is the user’s id from_liveClient.GetAsync(“me”). However, if you’re going to use an ID, say stored in a remote DB, the app-specific one would be better. If the data is ever compromised, it would be harder for someone to use against other Live-based apps or services linked to the user.

A couple web-based pages where you can view a decoded JWT are and The latter looks a little funky in IE but it works. The Federation Lab page will also encode a JWT, but neither one will actually validate the signature.

Registering an Application

I’ve found that it easiest to first associate a Windows Store app from within Visual Studio. Right-click on the project, select Store> Associate App with the Store… to do this. Once it’s done, under the Dashboard on the developer site (, find the app and click on its Edit link. Select Services. You’ll see a link to navigate to Live Services, e.g. “If you have an existing WNS solution or need to update your current client secret, visit the Live Services site.”

From there, you’ll see the “If your app uses Live Connect services, review:” heading and can use the Authenticating link to get your Client secret (which should only be used server side because you should be just sending a valid JWT).


Copy the Client secret to Notepad or similar so you will have it available to place in the web.config of the Web API service. Then use the Representing your app link to fill in the details on the app, such as the redirect URI:


The Redirect URI will be the LiveCredential used in your Windows 8 app. So make a note to have that available.

Note: Generally, you’ll want to restrict JWT issuing unless you have more than one store app that uses the same backend service. Don’t worry, this doesn’t affect also using a Windows Phone app.

If you are using the service with a Windows Phone app, you will also need to visit and select your app from My Apps, then API Settings and enable Mobile client app. This page is also where you will find your Client ID. Not to be confused with the Client secret, this is a value you will use for the LiveCredential in a Windows Phone app. (Incidentally, if you compare the MainPage.xaml.cs files in my Win8/WP8 projects you’ll see that this is the only difference aside from a few usings).

The App and Service Samples

I’ve provided two barebones apps for Windows 8 and Windows Phone, along with a Web API service. What they demonstrate is a way to stay signed into an app securely, pass a JWT to the server along with a POST, validate the JWT and return data. Live JWTs are issued with a 24-hour expiration. So even though your client app may not require logging in more than once, this means the app still needs to keep track of the latest expiration time and request a new token if needed. Otherwise the server will refuse to return data if it can’t validate the token.

The way I prefer to handle this is to have the server extract the expiration when it receives the JWT and return that to the client in the response headers. My samples don’t store the expiration in IsolatedStorage nor do anything to examine it under various usage scenarios, other than when launching. In any production code, you’d want to be sure to incorporate whatever’s needed to ensure a smooth, error-free experience for your users.

I spent a fair amount of time looking into the server-side code and decided to use the System.IdentityModel.Tokens.JwtSecurityTokenHandler for validation. I’d tried another library and fed it a token with a purposely altered signature, which it didn’t reject. They may have fixed it since, but I know this one works. All requests are routed through a handler set up in Global.asax.cs. Configuration settings unique to the app registration and server are stored in Web.config, e.g:

<add key=”AllowedAudience” value=”” />

<add key=”ClientSecret” value=”[APP CLIENT SECRET]” />

<add key=”Issuer” value=”urn:windows:liveid” />

These are placed inside appSettings.

Global.asax.cs will need to have references to System.IdentityModel and System.IdentityModel.Tokens added. Under the Application_Start method, add:


Note: Once this is implemented, along with the code below, the service will only work with valid JWTs. During initial setup, just to see that the service is working, comment this line out. You can enter a URL in a browser, such as http://[MACHINENAME]/AuthTestWebAPI/api/values and should see a JSON test string, e.g. [“value1″,”value2”].

Create a Configure method:

private static void ConfigureTokenValidation(HttpConfiguration config)


config.MessageHandlers.Add(new TokenValidationHandler());


And here’s the TokenValidationHandler class:

Note that the JWT’s expiration is extracted from the Thread.CurrentPrincipal, which contains all the decoded JWT claims. The expiration is then injected back into the Request, using a custom header. I think this is the first time I’ve ever done this for an internal operation on a server, but hey it works and seems a reasonable enough way to pass the value onto the ValuesController that will return a response to the client. I prefer to leave times in Unix epoch seconds when shuttling them around between server and client rather than transform them to DateTimes. It’s a smaller, less encoded value.

On the client side, it’s important not only to have the expiration to know when to ask for a new JWT, but also to know not to ask. If you had code that kept asking for a new JWT every time the user visits a page, resumes an app or even when first launching, it creates a noticeable delay. In testing, I’ve seen it usually take about 6 seconds to acquire a JWT. So you want to do so only when necessary.

Another configuration step is to set up the AuthTestWebAPI project up for local testing. You can still use the same audience URI (and, in fact, need to). But under Properties > Web I’d recommend setting it up to run on a local IIS server under the machine name. That will allow testing on your local network. I use a Surface tablet and a phone for this. Select Local IIS, provide a URL with your machine name, and click on Create Virtual Directory:


Note: You’ll need to run Visual Studio as Administrator to do this!

And while on the subject of configuration and local testing, in the AuthTestWin8 project, open Package.appxmanifest, navigate to capabilities and be sure to select Private Networks (Client & Server) or you won’t be able to access an intranet URL via the application.


Testing with the Clients

Once the service is configured (including enabling the ConfigureTokenValidation method), try running the client apps. If everything is working, you should see something like this:


Try hitting the Test Server Auth button a couple times. Note that the Time value changes, but not the Expiration. That’s because the expiration time is being compared to the last known expiration time (again, something you’d normally store in IsolatedStorage). This way, an unnecessary call to the Live servers is avoided. You will notice, however, with the Windows Phone app that upon launch the app will always get a new token, while the Win 8 app will not. This is something, again, where I’d use IsolatedStorage to store the token and expiration time and check the last known expiration time to see if a new token is required. If not, the stored token could continue to be passed to the server.

Resetting the Permissions Dialog

Sometimes you want to return to a state where you can mimic the user’s initial installation experience, including seeing the Live Permissions dialog. It may come as a surprise, but uninstalling/reinstalling the app won’t do it. What you need to do is visit, log on under whatever user account you’re using for testing and click on the Manage apps and services link ( On that page, look for the app, e.g. AuthTest, click on Edit and remove it. This will allow you to start over again.

Make it Musical

When I first started taking guitar lessons, my instructor told me that while it would be hard at first to sound good (it’s still hard, bro) to “always keep it musical.” What he meant and what I try to explain to my son as he progresses as a guitarist is to make it sound like a song. Don’t get wrapped up in the mechanics or lose the beat.

Yesterday, I was with our other boy and we stopped into Staples to get some school supplies. This was my first opportunity to play around with both an iPad Air and the new Mini, which is the one I’d get if when I start doing cross-platform development for iOS. They are both really nice devices and very light. I had an iPad (3) and the Air blows it away. Yesterday evening toting my Surface to a book seminar I’m part of it felt heavy in comparison.

Yet this was also my first time really experiencing iOS 7. And one thing that struck me is that the animations seemed rather clunky. How could this be? The display tag below it proudly extolled the presence of the mighty A7 processor. It’s not a hardware issue. I was surprised how rough things like the transition between portrait and landscape are. Not to make comparisons too much, but Microsoft did a pretty good job on that in Windows 8.x.

It wasn’t until we were driving home that it struck me what it was. Whoever designed those animations failed to make them musical. I had happened to turn the radio on, which was set to NPR. While I’m not much of a Classical music fan, I appreciate certain composers and pieces. The overture from Verdi’s La Forza del Destino was playing. As it opened, I suddenly pictured in my mind animating tiles and color transitions in time with the music and reflecting the mood of the piece. Feel free to listen to it while you finish reading:

If you’ve ever seen Fantasia or Bruno Bozetto’s parody Allegro Non Troppo then you will have some idea what I am talking about. The next time you make an animation or transition, try setting it to music while you’re working on it. One thing these master composers had down is timing and mood.

In a subsequent post, I’ll show a recent example where I was setting animation and transitions to sound effects for an animated, vector-based splash screen. Ordinarily I wouldn’t add one to an app, preferring to get right down to business, but this is for a game and it’s  also meant to add a little branding and some personality. One thing I found is that visual perception effects the way the user connects sound and sight. Sometimes you have to futz with timing so that a sound either starts earlier or later.

That’s “Code” Comfort

I’ve been working on a mobile app that will support adding vector-based mapping polygons. Using California and Massachusetts to do a test on MULTIPOLYGON states and a map extent spanning the lower 48, I imported the data, ran the code and when I saw the visual, thought something was messed up:
How could the code be putting California at the top of the image? I went back to my source map and sure enough, the northern tip of California really does go as high as central Massachusetts. It occurred to me that it could be because of the Lambert Conformal Conic projection for the contiguous U.S. that I’m using. But it turns out the northern boundary of California is 42° and so is the southern boundary of western Mass (or at least it seems that was the intention at the time, given the quality of surveying and certain conditions facing surveyors – see the Granby Notch story ( .


Incidentally, several states share 42° as an official boundary:

File:42nd parallel US.svg
Sometimes our notions of things, based on certain conceptions, distort reality. I can see where my perceptions of California as being in the southwestern part of the country and being mostly warmer than the chilly, northeasterly Massachusetts would make it hard to believe they could have boundaries near the same latitude. At least I know my routines work. That’s “code comfort.” Still lots of work to do!

Labeling Graphs

Recently, WikiLeaks released a draft text of the intellectual property chapter of the Trans-Pacific Partnership agreement. In what is otherwise an excellent (and somewhat disturbing) analysis of the data done by Gabriel Michael, a Ph.D. candidate at George Washington University, there is one problem: I couldn’t read the labeling on the graphs very easily. In this case, since the data is heavily tied to connections between countries, it’s essential to understanding the relationships presented in the graphs.

To a degree, this was exacerbated by the layout of the Washington Post’s article template ( which is where I first viewed these. But even viewed on the author’s original site – somewhat larger – they can still be difficult to read (


Allow me to make it clear that I’m not picking on anybody here or denigrating some very fine scholarship. I’m just adding a couple of modest improvements in the hope that graphics such as these will be able to reach an even wider audience. They carry a message that really needs to be received by as many people as possible.

First, the obvious. I increased the font size. However, it’s (usually) more legible to also change to a sans-serif typeface…and, while we’re at it, let’s bump up the weight. So now we have:


It’s worth noting that I was able to save the image at a smaller size too. It’s 440 pixels wide (including a bit of white space) and could now conceivably be viewed on a phone.

There is another improvement that may be made: Getting rid of the thin black lines around the circles. They don’t fit with the rest of the imagery in the graphs. Furthermore, a hollow shape requires a bit more visual decoding by the viewer’s eyes. Of course, removing those lines also means reversing the text color and picking some solid color for the circles. I chose a grayish-blue, not too saturated, to provide a bit of contrast to the yellow-orange-red lines:


Again, this post is not meant to be anything more than constructive. We all have our strengths and weaknesses.


Generally, I think the simplification works, particularly in the redesign of the Boston subway map. But the last example ( a weekend schedule) struck me as better for the geographically knowledgeable local than for any out-of-town visitor. The map it replaces is horrible, but there must be some happy medium that would keep enough geographic context.

Comparing the geographically detailed map with a schematic version

As a visitor, I’d likely be looking at a potential destination, then figure out how to get there. Of course, who uses these maps anymore when every smartphone will just tell you which line to take? Although I found the hardest part of dealing with public transit that way (at least when last in Seattle) was figuring out which way to go when on foot in between buses.

Overall, an article worth reading. The visual tracking research and renderings depicting user perception are fascinating.

Music to Code By

When I was in college, I used to listen to music all the time when studying. I worked at KGLT (still one of the best alternative college stations in the country) as a DJ and the assistant manager (which meant sometimes being referred to by the music director – all innocence and sweetness – as the “ass. mgr.” in written communications). I had access to all kinds, but mostly liked grungy, thrashy music…and liked all of it loud. People would ask how I could ever study like that. But, believe it or not, the volume served to drown out external distractions and helped me focus.

I no longer find that true of the hard stuff. I still crank it up on occasion, but even find that on my bike rides or while running that I prefer thinking in relative silence. So while working, my musical choices have become more judicious. I still find Classical unappealing in this setting, needing a little more pep in the morning. (That’s why NPR always goes off  after 8:00 a.m!)

One of my favorites is Alberta Hunter’s Downhearted Blues: Live at the Cookery. If you’ve never checked out this wonderful performer, you owe it to yourself to not only enjoy the music, but also to fully consume her inspirational story.  There’s a good bio here but I was first introduced to her and her music by the documentary Alberta Hunter: My Castle’s Rockin’, which captures just how remarkable she was as a performer and a person. (You can find it here).

Accompanied on piano by the elegant gentleman and composer, Gerald Cook, Hunter really struts her stuff. Even at age 82 she still had the charm and impeccable timing that originally made her a star way back when. It’s worth watching just to see how a professional does it. I also find inspiring both her self-effacing modesty and her sometimes risque banter.

Most of all, Hunter has some wise advice – some of which will bring tears to your eyes if you’ve ever felt blocked or frustrated. Her words are without question informed by a life spent first working her way up the hard way to stardom, then chucking it all to change careers. She prudently fudged her age, conjured up a high school diploma, went to nursing school and worked in health care until forcibly retired in 1977 at the age of 82. Then resumed her musical career at an age when most people are probably just thinking about what the nursing home will serve for lunch today.

IKnow IEquatable

Well, now anyway. Sometimes I think the statement “Necessity is the mother of invention.” should – when applied to coders – be restated as “Necessity is the mother of fruitless hacks, StackOverflow searches and more code.” Catchy, eh?

Prior to my somewhat painful re-education (not going to use a diaeresis this time), I was operating under the ridiculous assumption that comparing to collections would be straightforward…if not downright simple. But my code kept telling me two identical collections were not. Of course a better coder would immediately recognize a reference problem underlying this. First I had blithely tried:

if (savedExercisesCollection != ExercisesCollection)
 for (int i = 0; i < ExercisesCollection.Count; i++)
 ExercisesCollection[i].Order = i;

App.StorageSettings["SettingsChanged"] = true;

But that was always returning true. Next, I turned to LINQ (’cause it is the solver of all problems, isn’t it?). Well, at any rate, my thinking was that it would actually compare the values. And it is elegantly concise:

if (savedExercisesCollection.Except(ExercisesCollection).Any())
 for (int i = 0; i < ExercisesCollection.Count; i++)
 ExercisesCollection[i].Order = i;
App.StorageSettings["SettingsChanged"] = true;

I had also tried SequenceEqual but with the same sad results…until I stumbled across the IEqualityComparer<T> IEquatable @

if (!savedExercisesCollection.SequenceEqual(ExercisesCollection))
 for (int i = 0; i < ExercisesCollection.Count; i++)
 ExercisesCollection[i].Order = i;

App.StorageSettings["SettingsChanged"] = true;

Now I was on the path to righteousness. All it would take is adding a comparer to my original class. I approached this with some trepidation since I’m relying on being able to serialize portions of that class. But the only way to know if something will blow up is to light the fuse. Turns out no worries.

I modified the class as follows:

 public class Exercise : IEquatable<Exercise>
 public List<Asset> AssetsList;

public Exercise(int id, int order, string description)
 Id = id;

Order = order;

Description = description;

AssetsList = new List<Asset>();

 public int Id { get; set; }

 public int Order { get; set; }

 public string Description { get; set; }

 public bool Equals(Exercise other)
 //Check whether the compared object is null.
 if (ReferenceEquals(other, null)) return false;

//Check whether the compared object references the same data.
 if (ReferenceEquals(this, other)) return true;

//Check whether the products' properties are equal.
 return Id.Equals(other.Id) && Order.Equals(other.Order);

The take-home lesson from this is that unless an ObservableCollection is instantiated from the same source as another they are not automatically comparable. I can see this knowledge coming in handy when rehydrating a chunk of JSON, for instance to compare a remotely stored to-do list with one on the client.

Did ya hear the one about the serial killer?

Turns out his victim was found floating in a tub full of corn flakes and milk. Bahhh, dahhh, dahhh, da.

Anyway, in this case it was more that the serializer got killed…by an uncoöperative class. (BTW, that’s not an umlaut over the second “o”. It’s a diaeresis. Lovely sounding term. More on the subject: Typically, this happens because the class has a constructor with parameters. I couldn’t get around that. Well, I don’t want to anyway. I also didn’t want to depart from my vanilla JSON serializer, although in the past I’ve found SilverlightSerializer to be a solution when all else fails…like serializing an entire model. (Why would you want to do that? Long story, for some other time).

The solution is to simply mark up the class with the DataContract attribute and use DataMember for each of the members you want to serialize. In my case, this had the advantage of not serializing a voluminous sub-list I don’t want included. And it allows this class to be used in several places, rather than creating a separate Dictionary or similar.

public class Exercise
 public List<Asset> AssetsList;

public Exercise(int id, int order, string description)
 Id = id;

Order = order;

Description = description;

AssetsList = new List<Asset>();

 public int Id { get; set; }

 public int Order { get; set; }

 public string Description { get; set; }

And, voila, we end up with something that can be saved to IsolatedStorage:

[{“Description”:”JUMPING JACKS”,”Id”:0,”Order”:0},{“Description”:”WALL SIT”,”Id”:1,”Order”:1},{“Description”:”PUSH UPS”,”Id”:2,”Order”:2},{“Description”:”CRUNCHES”,”Id”:3,”Order”:3},{“Description”:”STEP UPS”,”Id”:4,”Order”:4},{“Description”:”SQUATS”,”Id”:5,”Order”:5},{“Description”:”TRICEPS DIP”,”Id”:6,”Order”:6},{“Description”:”PLANK”,”Id”:7,”Order”:7},{“Description”:”HIGH KNEES”,”Id”:8,”Order”:8},{“Description”:”LUNGES”,”Id”:9,”Order”:9},{“Description”:”PUSH UP & ROTATE”,”Id”:10,”Order”:10},{“Description”:”SIDE PLANK”,”Id”:11,”Order”:11}]