locked
HealthVault support for MVC 3/4 RRS feed

  • Question

  • Hi,

    I'm developing a website using ASP.NET MVC 3 (and waiting for the release of MVC 4), and I have not been able to find any article (a.k.a. good piece of code) that talks about how to elegantly integrate the HealthVault API with the MVC pattern.

    At first, I would say I'm interested in developing an offline application, and I have a small example working. However, I still need to make the user authenticate into HealtVault first, in order to get the PersonId (which of course is needed when creating the OfflineWebApplicationConnection).

    Personally, i dont want to add a page that inherits from  HealthServicePage because that breaks the mvc pattern, and it seems kind of "out of date" for me.

    If anyone can point me in the right direction, it would be greatly appreciated.

    Thanks

    Tuesday, April 3, 2012 4:16 PM

Answers

  • I agree that everyone is using MVC and we should get our MVC SDK out.  We actually have one written a year and a half ago but have not fully reviewed it and made it for public release.  I will see what we can do to get it released.

    using System;
    using System.Collections.Specialized;
    using System.Diagnostics.CodeAnalysis;
    using System.Security.Principal;
    using System.Web;
    
    namespace Microsoft.Health.Web.Mvc
    {
        public class HealthVaultAuthenticationModule : IHttpModule
        {
            public void Init(HttpApplication context)
            {
                context.AuthenticateRequest += 
                    new EventHandler((s, e) => AuthenticateRequest((HttpApplication)s));
            }
    
            public void Dispose()
            {
            }
    
            private static void AuthenticateRequest(HttpApplication app)
            {
                PersonInfo personInfo;
                string authToken = app.Request.Params["wctoken"];
                PersonProvider provider =
                    HealthVault.GetPersonInfoProvider(new HttpContextWrapper(app.Context));
                if (!String.IsNullOrEmpty(authToken))
                {
                    personInfo = provider.RequestPersonInfo(authToken);
                    provider.SavePersonInfo(personInfo);
    
                    NameValueCollection query = HttpUtility.ParseQueryString(app.Request.Url.Query);
                    query.Remove("wctoken");
                    query.Remove("suggestedtokenttl");
    
                    UriBuilder newUrl = new UriBuilder(app.Request.Url);
                    newUrl.Query = query.ToString();
                    app.Response.Redirect(newUrl.Uri.OriginalString);
                }
                else
                {
                    personInfo = provider.LoadPersonInfo();
                }
    
                if (personInfo == null)
                {
                    app.Context.User = null;
                }
            }
        }
    }
    

    You can replace all the "provider" code with calls to WebApplicationUtilities.Load/Save PersonInfo.

    • Marked as answer by Franquitox Tuesday, April 3, 2012 6:17 PM
    Tuesday, April 3, 2012 5:22 PM

All replies

  • HealthVault Shell (account.healthvault.com) is running on MVC3 right now.  If you're making a web site, you shouldn't be using OfflineWeb connection since the user is logging in.

    If you use Reflector or DotPeek, take a look at the HealthServicePage code, it ends up just calling some utility functions that deserialize/serialize the cookies that handle authorization. You can copy/modify portions of that code and put it into an authentication module so that it runs before each request.

    Once you get the PersonInfo object, everything else is the same in terms of calls.

    Tuesday, April 3, 2012 4:24 PM
  • The idea of using the OfflineWeb connection it's for batch updating the values of the records (since I'm doing some statistical analysis) and the user experience may be way too slow otherwise.

    Regardless of that, It shocks me that there is no code out there for a basic MVC authentication, since it's a standard routine and everyone is using mvc nowadays. May be I should do it and post it somewhere.

    Anyway, thanks for your comment, I'll try to take a look at what you suggest


    Tuesday, April 3, 2012 4:34 PM
  • I agree that everyone is using MVC and we should get our MVC SDK out.  We actually have one written a year and a half ago but have not fully reviewed it and made it for public release.  I will see what we can do to get it released.

    using System;
    using System.Collections.Specialized;
    using System.Diagnostics.CodeAnalysis;
    using System.Security.Principal;
    using System.Web;
    
    namespace Microsoft.Health.Web.Mvc
    {
        public class HealthVaultAuthenticationModule : IHttpModule
        {
            public void Init(HttpApplication context)
            {
                context.AuthenticateRequest += 
                    new EventHandler((s, e) => AuthenticateRequest((HttpApplication)s));
            }
    
            public void Dispose()
            {
            }
    
            private static void AuthenticateRequest(HttpApplication app)
            {
                PersonInfo personInfo;
                string authToken = app.Request.Params["wctoken"];
                PersonProvider provider =
                    HealthVault.GetPersonInfoProvider(new HttpContextWrapper(app.Context));
                if (!String.IsNullOrEmpty(authToken))
                {
                    personInfo = provider.RequestPersonInfo(authToken);
                    provider.SavePersonInfo(personInfo);
    
                    NameValueCollection query = HttpUtility.ParseQueryString(app.Request.Url.Query);
                    query.Remove("wctoken");
                    query.Remove("suggestedtokenttl");
    
                    UriBuilder newUrl = new UriBuilder(app.Request.Url);
                    newUrl.Query = query.ToString();
                    app.Response.Redirect(newUrl.Uri.OriginalString);
                }
                else
                {
                    personInfo = provider.LoadPersonInfo();
                }
    
                if (personInfo == null)
                {
                    app.Context.User = null;
                }
            }
        }
    }
    

    You can replace all the "provider" code with calls to WebApplicationUtilities.Load/Save PersonInfo.

    • Marked as answer by Franquitox Tuesday, April 3, 2012 6:17 PM
    Tuesday, April 3, 2012 5:22 PM
  • And that is what I was looking for!! Thank you so much !!

    If you have already done it, you should release the MVC SDK, at least for developers to start testing it. I'm pretty sure you would receive a lot of feedback.

    By the way, I followed your advice, and I was taking a look at the HealthServicePage code (using DotPeek). It was a good idea, and it can be done, but its a bit confusing for someone who doesn't have a lot of knowledge in the API.

    Anyway, thanks again! 

    Tuesday, April 3, 2012 6:16 PM
  • I am also working on an MVC-based HealthVault application and I've taken your suggestion creating an HttpModule to handle authentication.  This code you've provided works brilliantly except one thing and I cannot seem to isolate it.  When I call WebApplicationUtilites.SavePersonInfoToCookie(), the cookie is generated and I can see it in the response object.  However, after the redirect, when I try to load it in my controller, the cookies collection is empty.  Now maybe this is just a quirk with MVC lifecycle that I am not yet familiar with, or maybe it's something weird about how the cookie was created, but any assistance is greatly appreciated!

    Josh.

    Wednesday, July 11, 2012 5:04 AM
  • I don't think there are quirks about MVC that would cause your cookies to not be saved. We use this code everyday for account.healthvault.com.

    When the cookie is written out and the following page that is redirected, are you on the same domain? Is the cookie written as secure and both the incoming/redirected url both SSL?

    General issues I've seen in the past with cookies is because domains changed and/or SSL changed so that the cookie isn't sent back up.

    When you say the cookies are empty, you mean off the httpcontext.request.cookies?

    Thanks.

    Wednesday, July 11, 2012 6:16 PM