You can create and update your ApplicationId configuration in our Developer/PreProduction environment by accessing https://config.healthvault-ppe.com. The App Manager tool in our HealthVault SDK also connects to this config site.
But this configuration site is only available in non-Production environments. Microsoft reviews the data access for each application before it goes live, in an effort to ensure that the data set is reasonable for the implied intent of the application. Therefore any updates to a Production configuration can only be performed by the Microsoft team. You must make the config changes in PPE first and then test/verify that they work with your app. Then you submit an email request to HvGoLive@microsoft.com so that we can review the changes and then push the changes for you.
If you are making major changes to your configuration and want the config updates to coincide with the deployment of new code, we are generally able to schedule the push of a config update to coincide with your deployment. We ask that you give us a few business days' notice for such a push, or a bit longer if the push will be outside of west-coast US business hours.
Applications are expected to Handle the HealthServiceCredentialTokenExpiredException. The best way to handle this error is to Redirect the user to sign-on again, the best place to implement it in your basepage’s page error handler. Here is some sample code which accomplishes the same, please note this code should be in our basepage or any page deriving from HealthServicePage :
/// <summary>
/// This error block handles the case of an expired user token. User
/// tokens expire after 24 hours or time set by persistent tokens
/// for the "keep me sign-in" feature. These tokens and are stored in the cookie,
/// which has no default timeout. Developers are encouraged to expire cookies
/// sooner, but this code handles the case where the cookie does not
/// expire and the browser window is left open for over 24 hours.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HealthServiceCredentialTokenExpiredException)
{
WebApplicationUtilities.RedirectToLogOn(HttpContext.Current);
}
ShowError(ex);
}
Your page will need to implement ShowError method or you comment it and re-throw the un-caught exceptions.
Here is some help on diagnosing some of the common modes of failure with HealthVault certificate management.
Access denied
The most common cause of this error is that the application can find the certificate but the account running the app does not have the proper permissions to utilize its private key at run-time. See the end of this article for more information on giving permissions manully, or use the App Manager tool in the SDK.
This error can also be triggered by attempting a read/write which the user has not authorized, or a number of other authorization-related errors. You may need to look at the stack trace in order to figure out where your error lies. But if you have never successfully connected to HealthVault from Machine X with AppId Y, the certificate is the best place to start.
Keyset does not exist
I have seen this in two different scenarios:
- Application certificate is in the cert store, but that certificate only contains a public key. So the app finds the cert but can't find the keyset that it wants.
- Application certificate is in the file system but the application's service account doesn't have permission on this folder or file. Having not run this scenario myself, I would have expected this to be another "access denied" but I learned today that it gives a "keyset does not exist" error.
Got a good question today from a long-time HealthVault Developer -- at least they are long-time in terms of the short history of HealthVault.
If your application certificate is not configured correctly, either on your app server or on the HealthVault server, the first time that you will see an error is the first time that your application tries to read or write data to/from the HealthVault platform. This means that your end users (or more likely your test accounts) can successfully go through Application Authorization before they will see this error.
The fact that you get through App AuthZ without seeing any errors may lead you to believe that your certificate must be correct, but that is not the case. If you see an "Access Denies" error the first time that you try to load a page containing health information, then the most likely cause of your issue is an improperly configured application certificate.
See the post linked above for more information on certificate management.
There is a parameter on the HealthRecordFilter object called MaxFullItemsReturnedPerRequest and it is set to 240 by default. If your search returns more than MaxFullItemsReturnedPerRequest items then you will get full items for the first max items and then HealthRecordItemIds for the remaining items. You can then retrieve the other items by ID.
If you are using the .NET HealthVault SDK then all of this logic is handled for you. The HealthRecordItemCollection returned by GetMatchingItems will appear to contain all of the items. Attempts to work with the guts of an item that is still on the server will trigger the retrieval of that information.
(update on 10/21/2009: the default for MaxFullItemsReturnedPerRequest is 240. I originally said 30 and that is incorrect.)
We get a lot of questions about managing your HealthVault application certificate. When your application initiates a connection to HealthVault, it uses its unique private key to encrypt the first handshake message that it sends. HealthVault then uses a public key to verify that the sender of this message is indeed a trusted host. This public key must be registered with HealthVault before such connections can be made.
Generating your key pair and installing your private key
You can generate your key pair in one of two ways:
- Use the MakeCert.exe tool which ships with the HealthVault SDK and is available on MSDN. This doc on MSDN has more information on using MakeCert.
- Use the Application Manager tool which ships with the HealthVault SDK. Application Manager makes it easy to create a new AppId and certificate pair at the same time. Application Manager does not handle the scenario of creating a new certificate pair for an existing application.
Once you have generated your key pair, you can install it for use by your application in one of three ways:
- Cert store, default name. Application Manager gives your certificate the default name, "WildcatApp-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx," and places it in the default location. The HealthVault instructions on using MakeCert also give the cert the default name and place it in the default location.
- Cert store, non-default name. To specify your certificate name, specify the full subject name of the cert (CN=) in the <appSettings> section of your web.config file as follows:
<appSettings>
<add key="AppCertSubject" value="[full_cert_subject_name]"/>
</appSettings>
- File system. If you choose to take this approach then make sure that the following two things are true:
- The IIS worker process has access to read the file
- The file is not stored in a location where it is visible on your web site. Don't put it inside your web application path but in a secure file path not visible in IIS.
- To store your certificate on the local file system, you must add an additional entry in your web.config to tell the HealthVault SDK code where to look for the certificate, as follows. (This is also added to the <appSettings> section.)
<add key="ApplicationCertificateFileName" value="C:\someFolderName\cert\HelloWorld-SDK_ID-05a059c9-c309-46af-9b86-b06d42510550.pfx" />
- Note: the file path is an absolute local file path; relative path names are not allowed
- If you configured your private key to require a password for use, then you can/must specify this password in your web.config by using the ApplicationCertificatePassword parameter
Registering your Public Key
In PPE, you can register your public key in one of two ways:
- Use the Application Manager tool in the .NET HealthVault SDK to upload a new ApplicationId and its certificate. Note that this workflow is only for creating new applications. You cannot add a new certificate to an existing application this way.
- Login to the Application Configuration Center at https://config.healthvault-ppe.com and click on the "Public Certs" tab. You can upload additional CER files here.
Note that each application in the HealthVault-PPE environment has exactly one HealthVault-PPE account that has been set up with config access. If you need to set up a new account with config access, you can request this access via a link on the App Config Center home page.
In Production, the only way to register your public key is to go through the HealthVault Go-Live process. If your application is already live and you need to update or replace its public key, you can file a request with HealthVault Developer Support here.
We've had a few forum questions lately on email addresses so I figured I would send out some clarifying info.
Most of you are aware that the Account and the Record are separate but related entities in HealthVault. Each user account can have varying degrees of access to one or many records. So when you start thinking "email" you have to wonder whether you want to email the account-holder or the record-holder. The account-holder's email can be retrieved by an application by calling PersonInfo.GetSelfRecord() and then looking for the PersonalContactInfo singleton object. The record-holder's email is in the record at PersonInfo.SelectedRecord.
You login to an account with a credential that is usually a LiveId but the email address / login name for this LiveId is not stored in HealthVault nor is it directly available via the HealthVault API. This LiveId email address is often the same as the account-holder email in HealthVault but there is no guarantee that this will be the case.
When a user creates a record in the HealthVault UI, they must specify an email address. If they just signed up for an account and this record is their Self record then the email address that they used at account sign-up may get copied into the input form but the user can change this. After record creation, a user can change any record email address to which they have access by using the "Edit Profile" link in the HealthVault shell.
Once you have that email address, you can use your own server to send email or you can use the HealthVault API to do so. If you elect to use the HealthVault API, note that you will need to make two config changes first, via https://config.healthvault-ppe.com:
- Add the Send Email method group on the Method Mask tab
- Specify the Email Domain from which your application's emails will originate. You will set the sender address when calling our email-sending methods and the HealthVault platform will check that this sender address matches the domain on file.
HealthVault provides a way for applications to email their end users without requiring access to PersonalContactInfo. This is a privacy feature. Regardless of whether this approach is used, an applications Terms of Use must make it clear to end users that the application may send them email.
SendInsecureMessageFromApplication has two signatures:
-
The
first signature lets you specify a list of recipients by (DisplayName, EmailAddress). You can use this in the case where you know the recipient email addresses via any of the data types mentioned above.
-
The
second signature lets you specify a list of recipients by PersonId. You can use this in the case where you don't know the account-holder's email address but you still want to contact them. This protects the user's privacy by never sharing their address. This function leverages the email address in the PersonalContactInfo field of the first Self record of the user.
SendInsecureMessageToCustodiansFromApplication takes a RecordId as a parameter. This method will send your note to every custodian of the record in question.
Note that all of these methods are called "SendInsecureMessage..." because email is not a secure protocol and you should not send health information through email. (Consult a lawyer if this is unclear.)
Questions on any of this? Please ask on the forum in order to get the quickest possible response.
It is possible for end users to delete a HealthVault record but this function is not featured prominently in the user interface. This is by design, as we don't want end users to accidentally delete a record.
In order to delete a record:
- Go to the HealthVault Shell: https://account.healthvault.com in the Consumer environment or https://account.healthvault-ppe.com in the Developer environment
- Use the left sidebar menu to "switch to" the record that you wish to delete
- Click the "Edit Profile" link under the record picture/folder icon near the upper left corner of the screen
- Below the [save] and [cancel] buttons, you will see this text:
"If you wish, you can delete this health record. Warning: This will delete all the information in the record. Learn more."
I didn't make the text above a hyperlink but it takes you to the DeleteRecord page in the Shell.
If an end user erroneously deletes a record, it is often possible to recover the deleted data by contacting HealthVault customer support.
This is a supplement to Eric's blog post on Data Type Versioning in HealthVault.
The HealthVault platform is capable of converting V2 items into the V1 schema and vice versa. In order to simplify things for app developers, the platform will convert all versions of a type into versions that it believes this app understands. It makes this assessment by looking at the base authz that has been configured for the app. If the app asks the user to authorize V1 then the platform will convert all instances to V1. Replace "V1" with "V2" or "both versions" in that previous sentence at it remains true.
Note that what the app asks for in its auth rules may sometimes differ from what the user has granted, especially in the case where you have changed your auth rules from including Type-V1 to Type-V2. If a user has already authorized Type-V1 and you change your auth rules to use Type-V2 then the platform will recognize that your app now uses Type-V2 and the user will not be prompted to re-authorize.
So if you change your code to deal with V2 instead of V1 but don't change your authorization rules then the platform will continue converting the elements into V1s. A typecast error will occur when you try to load these V1 instances into a V2 object.
The platform treats different versions of a single type a bit differently than it treats different types. When you query the platform for instances of a versioned type, the platform's default behavior is to treat this as a request for all versions of the type and to ignore the fact that your request implicitly specified a version. You can override this behavior by using the TypeVersionFormat property of the View property of your HealthRecordFilter when you search, i.e.
filter.View.TypeVersionFormat.Add(Encounter.TypeId);
If you are searching across multiple types then this TypeVersionFormat collection can contain multiple elements, each of which will only be applied when relevant.
So if you are moving from an older version to a newer version of one or more data types then you have two options to choose from:
1. Change your authorization rules such that the new versions are requested. The platform will see this at run-time and will therefore convert instances into the version that you want.
-OR-
2. Add one or more types to your HealthRecordFilter.View.TypeVersionFormat collection.
If you fail to do either of these options then you will get a typecast error at run time.
There are two different elements that you are likely to think about when you think "authorization:"
* the amount of access that your app requests -- required and optional auth rules
* the amount of access that any particular user has granted
Think of the first as a domain table, perhaps, and the latter as a collection of values or instances.
The authorization state that the HealthVault platform references at run-time is a set of access that has been approved for a particular application by a particular user on a particular record. With optional auth, different amounts of access can get approved for different (application, user, record) triples. This bundle of access is stored in the HealthVault authorization system along with the (app, user, record) triple.
The bundle of data access gets presented to the user during app auth is a function of what is configured in the online and offline auth rules in ACC. Changing what is configured in ACC does not change what users have already authorized. But if a user logs into a HealthVault-connected app and the platform sees that their currently-granted access doesn't match the required minimum that was configured in ACC, then the user is prompted to re-auth.
When a you add an optional auth rule to your application, by default it will not be shown to users in App Auth. There is a parameter to the Shell Redirect call which lets you specify one or more rules to be displayed – onopt#.
On the back end, the application configuration also supports setting this default show/hide behavior, or the checked/unchecked state of the checkbox next to your optional rule. We have not yet added this feature to the Application Configuration Center, so if you would like to set this parameter then you must contact the HealthVault team. Please send us the following:
ApplicationId
Rule Name(s)
preferred show/hide behavior for each rule
preferred check/uncheck behavior for each rule
If you aren't already working with the HealthVault team then you can reach us via either of the support options listed at http://msdn.microsoft.com/en-us/healthvault/bb870258.aspx.
If you are using Optional Access in your HealthVault authorization rules, then at times you may want to know whether a particular user has authorized an optional piece of the data type access. You can find out what actions are currently authorized for a {user, record, app} by calling PersonInfo.SelectedRecord.QueryPermissions. You can read more about this method at http://msdn.microsoft.com/en-us/library/microsoft.health.healthrecordinfo.querypermissions.aspx. You can also use a similar method, QueryPermissionsByType, http://msdn.microsoft.com/en-us/library/microsoft.health.healthrecordaccessor.querypermissionsbytypes.aspx.
HealthVault does *not* allow an application to ask what access a particular user has to a particular record, but it can ask what that user has authorized for use in this application.
I hope that clears things up a little.
If an end user uses the "Upload a file" workflow in the HealthVault shell (https://account.healthvault.com/viewitems.aspx?typeid=bd0403c5-4ae2-4b0e-a8db-1888678e4528&additem=True) to upload a CCR or CCD file, the HealthVault shell recognizes that the file is a CCR or CCD and stores a CCR or CCD item to the record instead of storing a File item.
This logic is part of the Shell and gets exercised at the application layer. So if you write your own application which writes new File items to a HealthVault record, this logic will not get applied to your uploads. CCR or CCD files that you write with the File typeId will get stored as Files.
In a nutshell: the Shell can recognize that what the user thought was a File should really be stored as a CCR/CCD. The platform does not perform this check before storing a File item.
Some of our developers have asked how to identify the most recent version of a HealthVault data type that has been revised. We are working to improved our naming conventions and documentation in this space, but until then here is a workaround:
- Go to the HealthVault Data Type Schema Browser at http://developer.healthvault.com/types/types.aspx
- Click on each version of your data type
- Look in the "transforms" list for an "upconversion" transform and/or a "downconversion" transform. The former means that newer versions must exist and the latter means that older versions must exist. So look for the type which has only a "downconversion" transform and you'll have found the newest version.
Here is a list of the data types that have been revised as of today:
- Family History:
- 6d39f894-f7ac-4fce-ac78-b22693bf96e6 is the first version and is listed first
- 22826e13-41e1-4ba3-8447-37dadd208fd8 is the second version and is listed second
- Immunization:
- cd3587b5-b6e1-4565-ab3b-1c3ad45eb04f is the second version but is listed first
- 3d817dbe-af42-4a9d-a553-d1298b4d08fc is the first version but is listed second
- Medication:
- 30cafccc-047d-4288-94ef-643571f7919d is the second version but is listed first
- 5c5f1223-f63c-4464-870c-3e36ba471def is the first version but is listed second
- Procedure:
- 0a5f9a43-dc88-4e9f-890f-1f9159b76e7b is the first version and is listed first
- df4db479-a1ba-42a2-8714-2b083b88150f is the second version and is listed second
- Encounter:
- 3d4bdf01-1b3e-4afc-b41c-bd3e641a6da7 is the first version and is listed first
- 464083cc-13de-4f3e-a189-da8e47d5651b is the second version and is listed second
When trying to configure your Application Configuration Center, you will not be able to see these GUIDs but the HealthVault platform returns the data type list in the same order each time so you can use the reference chart above to make sure that you are requesting access to the right data types.
Update (20 Aug 2009): The Application Configuration Center now displays a version number for any version of a data type that isn't the newest version. No version number is displayed for the newest version, and old versions are indented and listed below the newest version, for example:
[ ] Medication
[ ] Medication (v1)
The first Medication is the most recent version, which in this case is v2.
If you see HealthVault platform throw the above exception when you run HealthRecordSearcher.GetMatchingItems() with specified type ID, the likely cause is that the locale of the application server is set to a value that doesn’t match the locale of the XSLT transform in HealthVault platform. The platform then fails to retrieve the XSLT transform with the application server’s locale. To work around this, we can add an element in Web.Config to specify the locale.
<configuration>
<system.web>
<globalization uiCulture=”en-US” culture=”en-US” />
</system.web>
</configuration>
When debugging issues like this, the request-response tracing described at http://msdn.microsoft.com/en-us/healthvault/cc135993.aspx should be quite helpful.