February, 2009

Posts
  • Eric Gunnerson's Compendium

    Age of Halo

    • 4 Comments

    My daughter downloaded the demo for Halo Wars a few days ago, and I spent a few hours playing it recently. It's from Ensemble, responsible for the "Age of <X>" (Empires I, II, III, and Kings), and it's similar enough that I've named it "Age of Halo".

    It's a pretty standard approach - build buildings, do research, train fighters, though there are some interesting constraints they've imposed this time around that I think will make the gameplay a bit different.

    I'm definitely going to pick it up when it comes out on March 3rd.  

  • Eric Gunnerson's Compendium

    Introduction to HealthVault Development #8: Related items

    • 4 Comments

    Our current application allows users to track their weight, but some of our users also want to track the time they spend walking. In this episode, we’ll extend our application to store and display that information.

    We will be storing that information in the Exercise type. First, we’ll need to head off to the Application Configuration Center (there’s a link at the bottom of the HealthVault Application Manager if you forget the URL…)

    Locate your application, and look at the online access that is currently defined. We could add a new rule named “Exercise”, but that would get unwieldy pretty quickly with lots of types. Instead, we are are going to group our rules based upon the type of access required. What we are defining right now is known as the application’s “base auth”, so we’ll put that concept in our names to make it easier later, when we explore the other kind of auth (if you’re too excited to wait, it’s called “optional” auth…)

    1. Edit the Weight rule. Change the name to “Base_All”.
    2. Add access to Exercise to this rule.
    3. Rename the Height rule to be “Base_read”.

    After you save the configuration (and perhaps wait a short time for the new configuration to be activated), run the application.

    You will be redirected to re-authorize the application, since your application is now asking for more data access than you had previously authorized it to have.

    That can make things a bit inconvenient (and confusing) for your users. You deploy a new version of your app that uses more types, and they have to reauthorize. The answer to that is the aforementioned optional auth, which I promise we’ll cover very soon.

    Now we can modify our code to record that exercise information.

    Housekeeping

    A little bit of housekeeping first, to fix a bug that you might have noticed. If you enter a new weight value, it doesn’t show up right away. This is because of a mistake I made when I wrote the first version.

    When the user enters a new weight, the data is posted back to the asp page, and Page_Load is called, then c_buttonSave_Click, then Page_Prerender, in that order (other stuff happens too). Which means that we’ve already rendered out the “current” set of information before we add new new value, which is why it doesn’t show up.

    The fix is to take all of the code that is currently in Page_Load, and move it into Page_Prerender.

    I assure you that this bug was in the code to provide a chance for you to debug your code, and certainly not an oversight from when I wrote the original code.

    Saving Exercise Information

    Go to default.aspx, and make label2 and c_textboxWalkingTime visible. This provides the UI that users use to enter their walking time.

    We’ll start by creating an Exercise instance:

    Exercise exercise = new Exercise();

    Next, we need to record when the exercise happened. We do this with the following:

    DateTime now = DateTime.Now;
    ApproximateDateTime approximateDateTime = new ApproximateDateTime(
        new ApproximateDate(now.Year, now.Month, now.Day),
        new ApproximateTime(now.Hour, now.Minute, now.Second));

    exercise.When = approximateDateTime;

    That’s an ugly bit of code, but that’s what you have to write right now. Our next release will let you write this as:

    exercise.When = new ApproximateDateTime(DateTime.Now);

    so you might want to give that a try.

    Now, we want to store the number of minutes that our user walked:

    int minutes = Int32.Parse(c_textboxWalkingTime.Text);
    exercise.Duration = minutes;

    We’re still missing an important piece of data – the kind of exercise. We would like to store this information so that programs can make decisions based on the specific activity. That can easily be done by defining a set of different activities (which is known as a “vocabulary” in HealthVault, and referencing one of those with the exercise.

    But that would miss an important piece of data – what the user said the activity was. Perhaps they want to enter “race walking” or “fitness walking”, or “walk in the park” and have the system show that as the activity when it displays the exercise information.

    To accommodate both of those uses, HealthVault uses a concept of a codable value, which is similar to the measurement type discussed in an earlier episode. It stores a Text value – which is whatever the user or program thinks it should be – and one or more coded values, which provide the specifics that programs would read.

    We’ll start by defining the CodedValue part. Looking at the docs for Exercise.Activity, we find it recommends the exercise-activities vocabulary (we could also have looked in the list of vocabularies).

    Each vocabulary item has a code, a display text, and an abbreviation. So, to code to walking, we use the following coded value:

    CodedValue codedValue = new CodedValue(“Walking”, “exercise-activities”);

    Where "Walking” is the code and “exercise-activities” is the vocabulary.

    We’ll use that to create the whole codable value:

    exercise.Activity =
        new CodableValue("Walking", new CodedValue("Walking", "exercise-activities"));

    In this case the Text and the codable value are the same, but in most cases the code is going to be considerably more terse than the Text value, or it may be a numeric value.

    If it was important to our application to store more information, or if we wanted to refer to more than one vocabulary, we could add additional coded values to the codable value. This is useful if there is more than one standard set of codes for a particular property.

    The codable values that are stored are not validated by the platform, which gives applications the flexibility to code to vocabularies that are not on the platform. We’d appreciate it, however, that you let us know if you’re coding to a vocabulary that you think should be on the platform.

    After all of that, we can save the Exercise instance to the record:

    PersonInfo.SelectedRecord.NewItem(exercise);

    Constructors

    In the last bit of code, I created the Exercise instance and then set the properties. That works fine, but all of the types in HealthVault declare constructors that take all the required values as parameters, and using that constructor is a good way of making sure you set all the required properties. Using that approach, our code would look like this:

    DateTime now = DateTime.Now;
    ApproximateDateTime approximateDateTime = new ApproximateDateTime(
        new ApproximateDate(now.Year, now.Month, now.Day),
        new ApproximateTime(now.Hour, now.Minute, now.Second));

    Exercise exercise = new Exercise(approximateDateTime, 
                     new CodableValue("Walking",
                                                new CodedValue("Walking", "exercise-activities")));

    int minutes = Int32.Parse(c_textboxWalkingTime.Text);
    exercise.Duration = minutes;

    PersonInfo.SelectedRecord.NewItem(exercise);

    Related Items

    There’s a problem in the code that I just wrote. The Exercise instance and the Weight instance were entered at the same time by the user, but that relationship isn’t stored in HealthVault. This is going to complicate our display code considerably, as we have no easy way of finding the Exercise instance that goes with a specific weight.

    We’ll use the Related items feature to connect them together.  We’ll simply add the Exercise instance to the related items list of the weight before we save it to the database:

    weight.CommonData.RelatedItems.Add(new HealthRecordItemRelationship(weight.Key));
    PersonInfo.SelectedRecord.NewItem(weight);

    Related items is pretty low-tech – the id of the related object is merely saved on the object. The platform doesn’t provide referential integrity or any of that database stuff, so applications must be prepared to come across related item links that refer to items that aren’t accessible to the application.

    Displaying the Exercise information in the table

    Whenever we fetch a weight, we want to see if there is a related exercise instance. Here’s the code that we’ll use:

    string minutes = String.Empty;
    foreach (HealthRecordItemRelationship relationship in weight.CommonData.RelatedItems)
    {
        if (relationship.ItemKey != null)
        {
            HealthRecordItem relatedItem =
                PersonInfo.SelectedRecord.GetItem(relationship.ItemKey.Id,
                HealthRecordItemSections.Core | HealthRecordItemSections.Xml);

            Exercise exercise = relatedItem as Exercise;
            if (exercise != null)
            {
                minutes = exercise.Duration.ToString();
            }
        }
    }

    This code walks through all the related items for an instance, and if there’s a key, it fetches the related item instance. It checks to see if the item fetched is an exercise, and if it is, formats the duration.

    The task of adding a new column named “Minutes” to the table and the minutes value to the body of the table is left as an exercise to the reader.

    Other Stuff

    There are a few other topics that out of scope of this episode, but worth mentioning anyway.

    Exercise is the new version of the AerobicSession type. Because of the type of data they store and the differences between the types, applications that will process AerobicSession data will likely want to handle it separately from Exercise data.  There is more information on this issue here.

    There is a second method of relating items together known as client ID, which is used by HealthVault connection center when it needs to link instances together (related items doesn’t work for it because of some architectural issues). I’ll cover client IDs in the future.

    Next Time

    Next time, we’ll do something with optional auth.

  • Eric Gunnerson's Compendium

    Introduction to HealthVault Development #7 – Data provenance

    • 5 Comments

     

    After our application is “in the wild” for a while, we receive some strange reports from our users.

    Some of the weight data being displayed appears to be suspect, and after investigation we find out that some of our users are also running an application named WeightOptimizer.

    Download and set up the Weight Optimizer application now, “optimize” one weight, and delete another. Run WeightTracker and look at the results.

    Now we’re going to figure out what to do in response to what is happening.

    <aside>

    One of the big values of HealthVault is that data can come from many different sources, and in general applications should use all data that is present in the record. However, some applications may want to determine the provenance of a specific piece of data, and that’s what this post is about…

    </aside>

    What we need to do is modify our application so that we fetch the source of the data, and then use that information to decide what we are going to do with it.  The information we want is in the Audits section, so we modify our fetching code to the following:

    HealthRecordFilter filter = new HealthRecordFilter(Weight.TypeId);
    filter.View.Sections |= HealthRecordItemSections.Audits;
    searcher.Filters.Add(filter);

     

    The information about the current state of the object is in the LastUpdated property, which is of type HealthServiceAudit. There is lots of interesting information here, but we’re going to concentrate on identifying a specific application. We’ll just add a column to the table to show the application name. Here’s our display code:

    AddHeaderCells(c_tableWeight, "Date", "Weight", "BMI", "App Name", "&nbsp;");
    foreach (Weight weight in weights)
    {
        double bmi = weight.Value.Kilograms / (height.Value.Meters * height.Value.Meters);
        string bmiString = String.Format("{0:F2}", bmi);

        string appName = weight.LastUpdated.ApplicationName;

        AddCellsToTable(c_tableWeight, weight.When.ToString(),
                        weight.Value.DisplayValue.ToString(), bmiString, appName);
        AddLinkToEditPage(c_tableWeight, weight.Key.Id);
    }

    A real application would likely want to implement a more sophisticated scheme. It might look at the audit information, and use the application id to put the information into classes such as the following:

    • Data the application wrote itself
    • Data from a list of applications tracked by this application
    • Device data that was uploaded through HealthVault Connection Center
    • Data from all other applications

    The classification would then be used to control application behavior.

    In addition to the information contained in the Audit fields, the HealthVault platform also supports signing individual data items with a digital signature that can later be used to help establish provenance. I hope to discuss digital signatures more in a future post.

    Next Time

    Next time we’ll add exercise tracking to WeightTracker.

  • Eric Gunnerson's Compendium

    Introduction to HealthVault Development #6 – Fixing a mistake

    • 2 Comments

     

    After we’ve released our application, some of our users complained that they accidentally entered an incorrect weight, and would like to have a way of fixing it.

    We will therefore extend our application to be able to update a weight. We’re going to do that by creating a separate edit page (editing in-line would be nicer, but this way is simpler).

    For the update page to know which weight it should be editing, we need a way to uniquely identify a specific weight instance. Every item that is stored in a HealthVault record has a property named Key of type HealthRecordItemKey. That type has two properties:

    • A guid named Id that uniquely identifies the instance.
    • A guid named VersionStamp that I’ll discuss in a little bit.

    For each Weight that is stored in our table, we’ll create a hyperlink to the update page that passes the Id. We do this by placing creating a HyperLink object and adding it to the table, and in this case there’s already a helper in the project that does that. So, we add the following after the call to AddCellsToTable():

    AddLinkToEditPage(c_tableWeight, weight.Key.Id);

    We also add a blank column header so the table doesn’t look weird:

    AddHeaderCells(c_tableWeight, "Date", "Weight", "BMI", "");

    That will give us a link to UpdateWeight.aspx. If you open that file, you’ll see that it has a few labels for displaying the current data, a place to enter the new weight, and an Update button.

    We need to write the code to fetch the Weight instance that the user wants to edit. We do this in the Page_Load() method in UpdateWeight.aspx.cs. First, we convert the Id from a string to a guid and stash it away for later:

    _idToUpdate = new Guid(id);

    Now we fetch the Weight instance. In our previous code, we used a filter to find the set of items that met a specific set of criteria, but in this case we’re looking to get a specific instance of the Weight type. We do that by calling GetItem():

    Weight weight = (Weight)
          PersonInfo.SelectedRecord.GetItem(_idToUpdate, HealthRecordItemSections.Xml);

    The _idToUpdate argument specifies which item we want to fetch, and the second one specifies what part of the object to fetch.

    Each HealthVault instance has a fair amount of data and metadata associated with it, and for performance reasons, applications should typically fetch only a subset of the sections.

    The sections are defined by the HealthRecordItemSections enumeration, which has the following items in it:

    Audits

    This section contains information about when an item was created or updated, which application and person performed the update, and when it happened. If it is passed, the Created and LastUpdated properties on the object will be populated.

    Core

    This section contains the core information for the object, including the EffectiveDate, State, Flags, IsPersonal, IsDownVersioned, and IspVersioned properties.

    EffectivePermissions

    An application can use the EffectivePermissions information to determine what operations it is authorized to perform on an object.

    OtherData

    This section contains information that is either auxiliary to the main purpose of the object, or information that is large and would not always be needed.

    OtherDataStream

    This section is similar to OtherData but provides stream-based access to the information

    Signature

    This section contains the HealthRecordItemSignatures property.

    Tags

    This section contains any textual tags that have been applied to the instance.

    Xml

    This section contains the type-specific information for the type. You will need to fetch this if you want to use any properties defined on the type.

    The section information can also be specified on filtered queries using HealthRecordFilter.View.Sections.

    Displaying the data

    Now that the data is fetched, we can populate the values into the UI controls:

    c_labelInstanceId.Text = _idToUpdate.ToString();
    c_labelWeight.Text = weight.Value.DisplayValue.ToString();

    Note that for the weight, we’re displaying exactly what the user originally entered by using the DisplayValue property.

    Updating the weight value

     

     

     

    The last task is to update the weight item, which uses a slight variation of the code we wrote to save the value in the first place. This goes in the MakeUpdate() method:

    Weight weight = (Weight)
        PersonInfo.SelectedRecord.GetItem(_idToUpdate, HealthRecordItemSections.Xml);

    int weightInPounds = Int32.Parse(c_textboxNewWeight.Text);
    weight.Value.Kilograms = weightInPounds / 2.204;
    weight.Value.DisplayValue = new DisplayValue(weightInPounds, "pounds");

    PersonInfo.SelectedRecord.UpdateItem(weight);

     

    One of the challenges in any system that allows multiple applications to read/write data at once is maintaining data integrity. Specifically, with the above code, we need to make sure that that nothing in the instance changes between the time we fetch the value and when the update happens.

    This is where the VersionStamp comes in. Whenever an instance is stored in HealthVault, the system creates a VersionStamp to store with it. In the update code, when the weight is fetched, it gets the current value of the VersionStamp. When UpdateItem is called, that version stamp is passed back to the platform. If it matches the current version stamp, then the platform knows that the object has not been modified, and the update operation is successful. If the version stamps do not match, the call to UpdateItem() will throw an exception, and the application will need to implement appropriate recovery methods to handle it.

    After the update is performed, the code redirects back to the application’s main page.

    Next time

    Next time, we’ll talk about some perplexing data that is showing up for some of our users.

  • Eric Gunnerson's Compendium

    25 Random things about Eric...

    • 1 Comments

    I did this for facebook, but thought I'd post a link here.

    25 Random things about Eric

Page 1 of 1 (5 items)