locked
Working with multiple child application IDs RRS feed

  • Question

  • I am working on a site to allow a patient to authorize HealthVault record access to multiple child applications.  The ApplicationId in the web config is set to our master application id.  I need a way to dynamically change the application id before the user is redirected to the HV login page.

    I have tried setting the config on Page_Init() like this:
    WebConfigurationManager.AppSettings["ApplicationId"] = childAppID;
    but the user is still sent to the master application login page (and debugging PersonInfo shows that they authenticated with the master id).

    What is the best way to override the ApplicationId in the config file so that a user can authenticate against a child id determined at run time?

    Thanks,
    KN
    Tuesday, March 10, 2009 11:04 PM

Answers

  • Okay, the above handles the first half of the equation-- sending the user off to HealthVault to authorize the child ID.  However, the second half is still missing: getting the UserID and RecordID back for use later on in an offline scenario.

    There isn't as great a solution for this now, and we're tracking this internally and hope to add better support to the SDK before long.  In the meantime, big thanks and credit to Jeff (one of our senior technical leads) for the approach here:


    The simplest approach would be for them to have Shell redirect to a page that doesn’t derive from HealthServicePage.  Extract the “WCToken” from the HttpContext.Current.Request.Params, create a WebApplicationCredential instance with the desired app-id and the token value, then create a WebApplicationConnection  with that credential, and then call GetPersonInfo on that connection.  If they want to save the user’s context into a cookie, they can call WebApplicationUtilities.SavePersonInfoToCookie(…). Then they can redirect back to the same page without the token on the query string.


    It would look something like this:


    1 string authToken = context.Request.Params[WebApplicationConfiguration.QueryStringToken];  
    2  
    3 if (!String.IsNullOrEmpty(authToken))  
    4 {  
    5     WebApplicationCredential cred =   
    6         new WebApplicationCredential(  
    7             applicationId,  
    8             authToken);  
    9  
    10     // set up our cookie  
    11     WebApplicationConnection connection =  
    12         new WebApplicationConnection(cred);  
    13  
    14     connection.Authenticate();  
    15  
    16     PersonInfo personInfo = connection.GetPersonInfo();  
    17  
    18     SavePersonInfoToCookie(context, personInfo, false, tokenTtl);  
    19  
    20     // redirect to fixed-up url  
    21     string newUrl =   
    22         StripFromQueryString(  
    23             context,  
    24             WebApplicationConfiguration.QueryStringToken,  
    25             WebApplicationConfiguration.PersistentTokenTtl);  
    26  
    27     context.Response.Redirect(newUrl);  
    28

     

    Note, the code for StripFromQueryString can be found in the WebApplicationUtilites.cs source file in the SDK.

    This code should be called from OnPreLoad() of the page.  If they want to mimic the other behavior of the HealthServicePage they should look at HealthServicePage.cs source file in the SDK.

    Friday, March 13, 2009 8:49 PM

All replies

  • I'm not familiar with using multiple application IDs in a single online application-- I'll ask a few questions and get back.

    However, I would be curious to know more about the scenario that requires this behavior.  Could you explain more why you are doing this?  That might help me to provide advice and assistance.

    The most common scenario for a single application to use multiple IDs internally is in an offline scenario, in which case you simply create new offline connection objects with different IDs, where each ID gets a new connection.
    Wednesday, March 11, 2009 12:22 AM
  • Try this and see if it works--

    In the constructor of your page, do the following:

        System.Configuration.ConfigurationManager.AppSettings["ApplicationId"] = "<INSERT GUID HERE>";
    Wednesday, March 11, 2009 1:39 AM
  • Thanks Lowell.  I'll give that a try in the morning.

    Our scenario is that we are handling the authorisation of record sharing for multiple clients (child applications).  So, we have one HV page that needs to authorise a patient record for whatever application id that is requesting it.  That's why we need to change the HV config on the fly.

    Is changing the AppSettings the only way to achieve this?

    KN (Kryptiq)
    Wednesday, March 11, 2009 1:58 AM
  • I believe that is the case-- the ID is used when the connection is established, and is associated with the connection itself.  In an online application, I believe there is an assumption that there is a single user interacting with a single application, so a single connection is created for the page request, using the underlying configuration value.  To change that, you need to change the ID in the constructor before the page events start firing and the connection is created.

    The offline scenario is designed to handle more bulk processing, and makes it easier to switch between IDs, but of course is offline and only works for offline scenarios.

    I believe if you're authorizing the user with a single application ID, and that ID can vary, that you can likely do this with an online application (if you need user interaction to do the authorization)-- you just need to catch the ID and change it in the constructor before the connection object is created when page events start firing.
    Wednesday, March 11, 2009 2:12 AM
  • I wonder if there is a potential problem in changing the Appsettings in the page constructor as suggessted - changing Appsettings has global effect and it will lead to issues in a multi threaded environment (like IIS).

    If 2 concurrent requests comes for 2 pages in the same application that needs to run in context of different application ids,  it could lead to wrong connection objects being created  when events are fired.

    Example order of execution where this issue could propup - Assume Page A is supposed to work with GUID-A as application id and Page B is supposed to work with GUID-B as applicationId

    Page A - Constructor Executes and sets the appsetting to GUID-A
    Page B - Constructor Executes and sets the appsetting to GUID-B

    Page A - Other events fire and uses GUID-B (WRONG)
    Page B - Other events fire and uses GUID-B

    One potential way SDK can be exteneded to resolve this is to check if there is predefined value present in the current HttpContext and then use it to override creation of connection objects.

    -Raj

    Raj HealthVault Developer Tool http://xray.getrealconsulting.com
    Wednesday, March 11, 2009 8:55 AM
  • Raj, you are right, this would definitely be a problem for concurrent users trying to authorize different application Ids. 

    Anyway, changing the App Id in the page constructor didn't give the desired results.  On the first page request after a server restart, I am able to change the AppSetting to any App Id and things work as expected.  However, I can't change it again after that - it holds on to that first value.

    KN (Kryptiq)
    Wednesday, March 11, 2009 5:03 PM
  • You could try overriding PreInit (and then call base class's implentatation AFTER you set the value).   Or even do a http module (which could be the one place you set the various contexts..

    But again, you will hit the concurrency issue and should not probably do that in a production level code...

    Raj
    Raj HealthVault Developer Tool http://xray.getrealconsulting.com
    Wednesday, March 11, 2009 5:16 PM
  • Changing the Web.config ApplicationId setting on the fly doesn't work (without restarting the application).  It seems that HV is storing away the Id somewhere when it first gets it (hence, I can change it on the first page request, but none after that).

    Can anyone tell me for sure if there is any other way to change the Application Id programmatically?  It seems like that should be configurable at runtime.

    Thanks!
    KN (Kryptiq)
    Wednesday, March 11, 2009 7:00 PM
  • We're discussing internally-- pretty sure there's a way to do it, it just isn't the most common scenario so it's taking a bit to get all the information together.  Apologies for the delay.

    One suggestion if someone wants to take a closer look themselves, I'm pretty sure that the Master/Child App ID sample demonstrates how to do this, I just haven't had a chance to open it up and take a look... busy day.

    If someone wants to check it out:  http://healthvaultd2c.codeplex.com/.
    Wednesday, March 11, 2009 8:08 PM
  • Thanks!  The example is close to what we need, but it shows OfflineAuthentication. 

    In a nutshell, we need a single online web application where a patient can log in to HV and authorize a record for use by a child application.

    So...
    UserA goes to our web app to authorize ChildApp1.
    UserB goes to our web app to authorize ChildApp2.
    etc...
    Wednesday, March 11, 2009 8:52 PM
  • We may have a better solution-- details coming shortly.  We're digging the code up and verifying today to make sure it works before we share.

    The main difficulty here is that this is a scenario we haven't directly focused on yet, and while we certainly feel it is valid, we haven't specifically written code around supporting it yet.  We're not preventing it, but the SDK as-is doesn't make it easy.  We may have a good workaround, however... stay tuned.  We'll definitely be looking at adding better support here in upcoming releases of the SDK.
    Thursday, March 12, 2009 7:45 PM
  • Try this-- the key is that we're looking at the problem the wrong way.  The goal isn't to change the internal App ID before the page loads, the goal is to redirect the user to log in and authorize a particular application ID.  That just means we need to look at how to redirect to login/authorization given a particular ID, which is a very different (and easier) problem.

    From: http://msdn.microsoft.com/en-us/healthvault/cc265056.aspx

    To prompt the user to log in and authorize if needed:

        RedirectToShellUrl(HttpContext.Current, “AUTH”, “appid=…”);

    To prompt the user to log in and force authorization:

        RedirectToShellUrl(HttpContext.Current, “APPAUTH”, “appid=…”);

    There are other parameters besides “appid” that are documented in the SDK as well.  Also, each child ID can be configured to return to different landing pages, so if you need the different child IDs to go to different final targets, that shouldn’t be impossible either.

    Let me know if that works, or if you’re still blocked.

    Thursday, March 12, 2009 9:23 PM
  • Okay, the above handles the first half of the equation-- sending the user off to HealthVault to authorize the child ID.  However, the second half is still missing: getting the UserID and RecordID back for use later on in an offline scenario.

    There isn't as great a solution for this now, and we're tracking this internally and hope to add better support to the SDK before long.  In the meantime, big thanks and credit to Jeff (one of our senior technical leads) for the approach here:


    The simplest approach would be for them to have Shell redirect to a page that doesn’t derive from HealthServicePage.  Extract the “WCToken” from the HttpContext.Current.Request.Params, create a WebApplicationCredential instance with the desired app-id and the token value, then create a WebApplicationConnection  with that credential, and then call GetPersonInfo on that connection.  If they want to save the user’s context into a cookie, they can call WebApplicationUtilities.SavePersonInfoToCookie(…). Then they can redirect back to the same page without the token on the query string.


    It would look something like this:


    1 string authToken = context.Request.Params[WebApplicationConfiguration.QueryStringToken];  
    2  
    3 if (!String.IsNullOrEmpty(authToken))  
    4 {  
    5     WebApplicationCredential cred =   
    6         new WebApplicationCredential(  
    7             applicationId,  
    8             authToken);  
    9  
    10     // set up our cookie  
    11     WebApplicationConnection connection =  
    12         new WebApplicationConnection(cred);  
    13  
    14     connection.Authenticate();  
    15  
    16     PersonInfo personInfo = connection.GetPersonInfo();  
    17  
    18     SavePersonInfoToCookie(context, personInfo, false, tokenTtl);  
    19  
    20     // redirect to fixed-up url  
    21     string newUrl =   
    22         StripFromQueryString(  
    23             context,  
    24             WebApplicationConfiguration.QueryStringToken,  
    25             WebApplicationConfiguration.PersistentTokenTtl);  
    26  
    27     context.Response.Redirect(newUrl);  
    28

     

    Note, the code for StripFromQueryString can be found in the WebApplicationUtilites.cs source file in the SDK.

    This code should be called from OnPreLoad() of the page.  If they want to mimic the other behavior of the HealthServicePage they should look at HealthServicePage.cs source file in the SDK.

    Friday, March 13, 2009 8:49 PM