Tuesday, December 27, 2011

Mobile & Global with HTML5, MVC & Windows Azure, Step 7: Globally-Deployed

In this series of posts we’re progressively demonstrating a mobile and global sample, Responsive Tours. The source code for all 7 steps is on CodePlex at http://responsivetours.codeplex.com.

Here in Step 7 of 7 we’re going to deploy the solution to a Windows Azure data center. In this step we will:

• Create hosted services in multiple data centers
• Configure traffic management
• Update the Access Control Service to support the new data centers
• Enable Content Delivery Network for image blobs
• Deploy the solution to multiple Windows Azure data centers around the world
• Set up automated traffic management
• Set up a friendly DNS for the solution

Creating Hosted Services in Multiple Data Centers
In Step 6 we deployed the solution as a Windows Azure Compute hosted service in a single Windows Azure data center (we chose the South Central US location, which is in Texas). Now imagine we are serving a worldwide audience, and that we’d like a global presence. We can achieve that by creating additional hosted services in other parts of the world.

There are currently 6 Windows Azure data centers to choose from: 2 in North America, 2 in Europe, and 2 in Asia. We’ll plan on running our solution in two additional places: Western Europe (Amsterdam) and East Asia (Hong Kong).
To streamline the work we need to do in this step, it’ll work out best if we create the hosted services now in the Windows Azure portal (noting their names and production URLs) but do not deploy our solution to them just yet. We need to note the production URLs for our hosted services. In our example, they are responsive-us.cloudapp.net, responsive-europe.cloudapp.net, and responsive-asia.cloudapp.net. Your names will be different, as they must be unique.

A decision to make at this point is whether to create three separate editions of your web site project. If you will be customizing content based on location (for example, using different languages or content for each locale) or creating a separate database for each data center (which would be necessary in a real setting for performance), you may want to split out the web projects separately or do the equivalent with clever build configuration. In our sample code we have simply made three copies of the project (named /us, /europe, and /asia), one for each data center.
Configuring Traffic Management
A nice feature of Windows Azure is the Traffic Manager service (currently in Community Technology Preview), which will allow us to have a single .com address for our deployment even though it will exist in 3 data centers on 3 continents.

To set up the traffic manager, we use the Windows Azure portal, choosing a unique name prefix for the Traffic Manager. In our example that name is responsive, making the Traffic Manager endpoint http://responsive.ctp.trafficmgr.com. This will ultimately be the endpoint we can use to access Responsive Tours regardless of location. We then enroll each of our three hosted services (US, Europe, Asia). Of course the hosted services aren’t deployed yet, but we’re doing this now because we’ll need the Traffic Manager URL for configuring security.

We get to choose a policy in our Traffic Manager configuration (performance, failover, or round-robin).  The best choice for this scenario would be Performance-based routing based on location, but we’re going to use Round Robin in our example since it is a demo, to prove that as you access the site at different times you will in fact be routed to different data centers. In our HTML code, we’ve changed the footer text of each site to indicate which location it is in so we will have an easy way to detect that when we visit the site.
Updating Access Control Service to Support the New Hosted Services

The Access Control Service we are using for authentication needs to be configured to allow the additional data centers. You might think we need to identify each hosted service as an additional Relying Party, but actually all we have to do is identify the Traffic Manager endpoint as an RP.

One other change we need to make is in the Windows Identity Foundation configuration in the Web.config file of our web project(s). In the wsFederation element, we need to set the realm to the Traffic Manager endpoint.

<federatedAuthentication>
  <wsFederation passiveRedirectEnabled="true" issuer="https://[MY-ACS-NAMESPACE].accesscontrol.windows.net/v2/wsfederation" realm="http://[MY-TRAFFIC-NAME].ctp.trafficmgr.com/" requireHttps="false" />
  <cookieHandler requireSsl="false" />
</federatedAuthentication>


Enabling Content Delivery Network for Image Blobs

Our promotional images are residing in Blob Storage in the South Central US Data Center. We can enable efficient worldwide access through the Windows Azure Content Delivery Network. The CDN will use a worldwide network of 24 edge cache servers to serve images with high performance based on locale.

Configuring the CDN for our storage account in the Windows Azure portal provides us with a special CDN endpoint for our images. We change our view pages to use the new endpoint.

<!-- begin - homepage promos -->
<div class="home_promo_container">
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(http://responsive.blob.core.windows.net/images/@(ViewBag.Promos["1"].ImageURL));">
   <h2 data-bind="text: PromoTitle1"></h2>
   <p  data-bind="text: PromoText1"/>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(http://responsive.blob.core.windows.net/images/@(ViewBag.Promos["2"].ImageURL));">
   <h2 data-bind="text: PromoTitle2"></h2>
   <p  data-bind="text: PromoText2"/>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(http://responsive.blob.core.windows.net/images/@(ViewBag.Promos["3"].ImageURL));">
   <h2 data-bind="text: PromoTitle3"></h2>
   <p  data-bind="text: PromoText3"/>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="clear_both"></div>

Deploying the Solution Worldwide

Now it’s time to deploy our hosted services to the US, European, and Asian data centers. As in Step 6, we can use Visual Studio to package and publish the solutions. When we’re done, we should see 3 deployments ready in the Windows Azure portal.

Once we’ve deployed all 3 hosted services, we’re in a position to serve a worldwide audience.

Testing the Global Site

Now we’re ready to see our mobile and global solution work in its global deployment. All we have to do is visit our Traffic Manager endpoint with a desktop browser, tablet, or phone. In our example the endpoint is http://responsive.ctp.trafficmgr.com. The site comes up just as we expect it to, and as we do this from multiple sessions and devices we can see that the location (shown in the page footer) varies between South Central US, Western Europe, and East Asia. Note, you may get an occasional hiccup because we are not routing traffic based on location.


Friendly DNS
One last thing we can do is give our web site a friendly DNS name. We’ll do this by purchasing the domain responsive-tours.com from GoDaddy. Now you can access the global site at http://responsive-tours.com. There are a number of ways we can forward the domain, we’ll deliberately choose here to do simple forwarding--so you can see the URL change when you visit the site  to show the Windows Azure Traffic Manager is at work.

Summary
In Step 7 we enabled the CDN for edge caching of blob images, deployed the solution globally to 3 continents, and used the Windows Azure Traffic Manager to manage traffic. Our site now has the following functionality:

• Embodies responsive web design and runs on desktops, tablets, and phones.
• Uses HTML5 and open standards on the web client
• Uses the Microsoft web platform on the web server.
• Provides server-side dynamic content (promotional items)
• Provides client-side dynamic content (Bing Maps)
• Is set up for Windows Azure Compute
• Can authenticate against web identities
• Is hosted in Windows Azure Compute
• Stores images in Windows Azure Blob Storage
• Stores promotional content in SQL Azure Database
• Uses Content Delivery Network for worldwide image caching
• Manages global traffic across 3 data centers on 3 continents

In this series we’ve seen the power that comes from combining HTML5, open standards, mobile devices, and responsive web design on the front end with the Microsoft web platform and Windows Azure cloud computing on the back end: true “mobile and global” web/cloud solutions that truly run anywhere and everywhere.

Mobile & Global with HTML5, MVC & Windows Azure, Step 6: Cloud-Deployed

In this series of posts we’re progressively demonstrating a mobile and global sample, Responsive Tours. The source code for all 7 steps is on CodePlex at http://responsivetours.codeplex.com.

Here in Step 6 of 7 we’re going to deploy the solution to a Windows Azure data center. In this step we will:
• Migrate the local SQL Server database to a SQL Azure database in the cloud
• Migrate the promotional item image files to Blob Storage
• Update how we handle session cookies to be compatible with Windows Azure
• Package the application and publish it to the Windows Azure Compute Service
• Configure the Access Control Service for the hosted service

Migrating the Database to SQL Azure
Since Step 3 we’ve been using dynamic content for promotional items, driven by a Promotions table in a SQL Server database. Now we’ll need to move that over to a SQL Azure database in the cloud. To do that, we use the Windows Azure portal to create a virtual database server in the cloud. This involves selecting a data center, specifying an admin username/password, and setting up firewall rules.


Once the database server is created we need to create a Tours database. We can go with the smallest size (1GB) since we’re only storing a small amount of data in this sample.


From this point, working with the database is much like working with SQL Server. We have the choice of using familiar tools like SQL Server Management Studio or managing design and data through the SQL Azure portal. We need to design the Promotions table and migrate the promotional item records we previously created in a local database.



There’s one last item to attend to on the database. With our database now in SQL Azure, we must change the connection string in the web project’s Web.config to reference the cloud database.

  <connectionStrings>
    <add name="Tours" connectionString="Data Source=[MY-SQL-AZURE-SERVER].database.windows.net;Initial Catalog=Tours;UID=[MY-SQL-AZURE-USER]@[MY-SQL-AZURE-SERVER];PWD=[MY-SQL-AZURE-PASSWORD];" />
  </connectionStrings>
 
Migrating Images to Blob Storage

Up till now our promotional images have been part of the web project. To make them truly dynamic like the rest of the promotional content we should be able to change them out quickly and easily. We can achieve this by relocating the image files to Windows Azure Blob Storage, where they can be accessed as Internet URLs if we set appropriate permissions.

We first need to create a Windows Azure storage account in the Windows Azure portal. We’ll need to capture the storage account’s unique name and a storage key.



With the storage account created, we can create a container (allowing public read access) and upload our promotional images to it. Use a tool like Cerebrata Cloud Storage Studio or Azure Storage Explorer for this.


With the images in a new location we must change the promotional item markup on our HTML pages to match. We use the blob container’s URL format, [STORAGE-ACCOUNT-NAME].blob.windows.net/[CONTAINER-NAME]/[BLOB-NAME].
<!-- begin - homepage promos -->
<div class="home_promo_container">
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(http://responsive.blob.core.windows.net/images/@(ViewBag.Promos["1"].ImageURL));">
   <h2 data-bind="text: PromoTitle1"></h2>
   <p  data-bind="text: PromoText1"/>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(http://responsive.blob.core.windows.net/images/@(ViewBag.Promos["2"].ImageURL));">
   <h2 data-bind="text: PromoTitle2"></h2>
   <p  data-bind="text: PromoText2"/>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(http://responsive.blob.core.windows.net/images/@(ViewBag.Promos["3"].ImageURL));">
   <h2 data-bind="text: PromoTitle3"></h2>
   <p  data-bind="text: PromoText3"/>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="clear_both"></div>

Updating Session Cookie Handling for Windows Azure
By default, our WIF-enabled ASP.NET MVC3 application is encrypting session cookies using the Data Protection API (DPAPI). DPAPI is not compatible with Windows Azure, so we need to add some code to encrypt cookies with RSA using a certificate. We do this in global.asax.cs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Web;
using Microsoft.IdentityModel.Web.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace html5_mvc_razor
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        /// Retrieves the address that was used in the browser for accessing 
        /// the web application, and injects it as WREPLY parameter in the
        /// request to the STS 
        /// </summary>
        void WSFederationAuthenticationModule_RedirectingToIdentityProvider(object sender, RedirectingToIdentityProviderEventArgs e)
        {
            //
            // In the Windows Azure environment, build a wreply parameter for  the SignIn request
            // that reflects the real address of the application.
            //
            HttpRequest request = HttpContext.Current.Request;
            Uri requestUrl = request.Url;
            StringBuilder wreply = new StringBuilder();

            wreply.Append(requestUrl.Scheme);     // e.g. "http" or "https"
            wreply.Append("://");
            wreply.Append(request.Headers["Host"] ?? requestUrl.Authority);
            wreply.Append(request.ApplicationPath);

            if (!request.ApplicationPath.EndsWith("/"))
                wreply.Append("/");
            e.SignInRequestMessage.Reply = wreply.ToString();
        }


        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

            routes.MapRoute(
                "Map", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Map", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
        }

        void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
        {
            //
            // Use the <serviceCertificate> to protect the cookies that are
            // sent to the client.
            //
            List<CookieTransform> sessionTransforms =
              new List<CookieTransform>(new CookieTransform[] {
                new DeflateCookieTransform(), 
                new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(e.ServiceConfiguration.ServiceCertificate) });
            SessionSecurityTokenHandler sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
            e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
        }

    }
}


If we were using SSL for this site we'd use the SSL certificate. Since we're not, we upload our own certificate to the Windows Azure portal for this purpose and specify it in our Web.config.

  <microsoft.identityModel>
    <service>
      <audienceUris>
        <add value="http://MY-SERVICE-NAME.cloudapp.net/" />
      </audienceUris>
      <federatedAuthentication>
        <wsFederation passiveRedirectEnabled="true" issuer="https://[MY-ACS-NAMESPACE].accesscontrol.windows.net/v2/wsfederation" realm="http://MY-SERVICE-NAME.net/" requireHttps="false" />
        <cookieHandler requireSsl="false" />
      </federatedAuthentication>
      <applicationService>
        <claimTypeRequired>
          <!--Following are the claims offered by STS 'https://[MY-ACS-NAMESPACE].accesscontrol.windows.net/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->
          <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
          <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
          <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />-->
          <!--<claimType type="http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider" optional="true" />-->
        </claimTypeRequired>
      </applicationService>
      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedIssuers>
          <add thumbprint="ED98B07917624AEE89EDDC086589A6149ADE6859" name="https://[MY-ACS-NAMESPACE].accesscontrol.windows.net/" />
        </trustedIssuers>
      </issuerNameRegistry>
      <serviceCertificate>
        <certificateReference storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="308EFDEE6453FFF68C402E5ECEEE5B8BB9EAA619"/>
      </serviceCertificate>
      <certificateValidation certificateValidationMode="None" />
    </service>
  </microsoft.identityModel>


Publishing the Site to Windows Azure Compute
Back in Step 4 we set the site up for hosting in Windows Azure Compute but up till now we’ve only been running it locally in the Windows Azure Simulation Environment. Now we want to deploy the solution to a Windows Azure Data Center.

We first create a Hosted Service in the Windows Azure management portal. In our example we chose the South Central US data center and call the service responsive, which means its production URL will be http://responsive.cloudapp.net. Your name will be different as they must be unique.

After setting the number of VM instances in the Windows Azure project’s .cscfg file (to 2, the minimum for high availability), we are almost ready to deploy but we need to make one change to the project first relating to security.

Our impending change in deployment location will cause ACS authentication to fail unless we change our web project's configuration settings (which we'll do now) and ACS configuration (which we'll do later in this post). In the web project's Web.config file, change the realm attribute in the wsFederation element to reflect the new production URL.

<federatedAuthentication>
  <wsFederation passiveRedirectEnabled="true" issuer="https://[MY-ACS-NAMESPACE].accesscontrol.windows.net/v2/wsfederation" realm="http://MY-SERVICE-NAME.net/" requireHttps="false" />
  <cookieHandler requireSsl="false" />
</federatedAuthentication>


We can now proceed to package and deploy our solution, which can done directly from Visual Studio. We do this in Solution Explorer by right-clicking the Windows Azure project (ResponsiveSite.Azure) and selecting Publish. A wizard then guides us through the publishing action, which packages up the solution and its configuration, uploads both to the cloud, allocates VM instances, and deploys an image to them that includes our web site.

The Publish action can take 10-20 minutes, and when complete we’ll see the hosted service showing a status of Ready in the Windows Azure management portal.


Configuring Access Control Service for the Hosted Service
In Step 5 we configured the Windows Azure Access Control Service to allow our local development endpoint as a Relying Party. Now we need add another RP, our hosted service endpoint (http://responsive.cloudapp.net in our example) using the Windows Azure portal.

Running the Solution in the Cloud
All that remains now is try things out. Our hosted service in the cloud is accessed at a production URL based on the unique name we chose when the hosted service was created – http://[SERVICE-NAME].cloudapp.net. Our example deployment is at http://responsive.cloudapp.net. When we access this URL, we see the hosted service respond, now using a database in the cloud for promotional content and promotional images served up from blob storage. As in the past we first have to sign in with a web identity. In short, the site looks and acts like it has in previous steps except that it is now running in a Windows Azure data center accessible on the Internet.
Summary
In Step 6 we moved to the cloud, by hosting our web site in Windows Azure Compute, our promotional images in Blob Storage, and our promotional content in SQL Azure Database. Our site now has the following functionality:
• Embodies responsive web design and runs on desktops, tablets, and phones.
• Uses HTML5 and open standards on the web client
• Uses the Microsoft web platform on the web server.
• Provides server-side dynamic content (promotional items)
• Provides client-side dynamic content (Bing Maps)
• Is set up for Windows Azure Compute
• Can authenticate against web identities
• Is hosted in Windows Azure Compute
• Stores images in Windows Azure Blob Storage
• Stores promotional content in SQL Azure Database
We've come pretty far, but there's more we can do. In the next step, we'll deploy the application globally to multiple Windows Azure data centers around the world.

Monday, December 26, 2011

Mobile & Global with HTML5, MVC & Windows Azure, Step 5: Secured

In this series of posts we’re progressively demonstrating a mobile and global sample, Responsive Tours. The source code for all 7 steps is on CodePlex at http://responsivetours.codeplex.com.

Here in Step 5 of 7 we’re going to make the site secure by requiring sign-in with a web identity. To be friendly we’ll let users apply an existing web/social identity and give them a choice of several identity providers. In this step we will:

• Configure the Windows Azure Access Control Service with several identity providers
• Implement authentication in the web site with Windows Identity Foundation
• Retrieve claims information (display name) after the user authenticates
Configuring the Access Control Service

The Windows Azure Access Control Service provides claims-based security federation. We’ll be using it to handle authentication. After creating an Access Control Service namespace in the Windows Azure portal it’s necessary to configure it, which will involve several configuration screens.
First off we authorize identity providers. For this sample we’ll use the 3 that are easiest and already built-in to the service: Google, Windows Live ID, and Yahoo!

Next we configure a relying party (RP)—that is, an application permitted to authenticate with this ACS namespace. For the time being, that will be our local machine Window Azure Simulation Environment address, http://127.0.0.1:81/. In later steps we’ll add our deployment addresses in the cloud.

We configure claim rules for our relying party. Claims are name-value pairs our application will be able to retrieve after authentication. Google and Yahoo! will give us a display name, while Windows Live ID does not supply that value.

Finally, the Application Integration area of the portal gives us a WS-Federation Metadata address which we’ll use in the next section.

Implement Authentication with Windows Identity Foundation
We can instrument our application for claims-based authentication with Windows Identity Foundation (WIF). WIF can be used to directly authenticate against security token services (STSs) for domain identity and web identity; and we can also use it to talk to the Windows Azure Access Control Service.

We add WIF to the solution by right-clicking the web project and selecting Add STS reference. That brings up a wizard in which we enter our WS-Federation Metadata address (see previous section). WIF updates the application and its configuration for claims-based security.


The WIF wizard adds the following configuration to Web.config: 
  <microsoft.identityModel>
    <service>
      <audienceUris>
        <add value="http://127.0.0.1:81/" />
      </audienceUris>
      <federatedAuthentication>
        <wsFederation passiveRedirectEnabled="true" issuer="https://MY-ACS-NAMESPACE.accesscontrol.windows.net/v2/wsfederation" realm="http://127.0.0.1:81/" requireHttps="false" />
        <cookieHandler requireSsl="false" />
      </federatedAuthentication>
      <applicationService>
        <claimTypeRequired>
          <!--Following are the claims offered by STS 'https://[MY-ACS-NAMESPACE].accesscontrol.windows.net/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->
          <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
          <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
          <!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />-->
          <!--<claimType type="http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider" optional="true" />-->
        </claimTypeRequired>
      </applicationService>
      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedIssuers>
          <add thumbprint="ED98B07917624AEE89EDDC086589A6149ADE6859" name="https://MY-ACS-NAMESPACE.accesscontrol.windows.net/" />
        </trustedIssuers>
      </issuerNameRegistry>
      <certificateValidation certificateValidationMode="None" />
    </service>
  </microsoft.identityModel>
If we were doing an in-depth application, we’d configure some parts of the site to require authentication and other parts not to. As this is a demo, we’ll just keep things simple and require authentication to access any of it.
Retrieve Claims Information
We’d like to retrieve and show a display name when one is available (some of the identity providers will give us this claim and some do not). Below we add code to the MVC project's Home controller to retrieve a display name claim if available and fashion a welcome string. The welcome string will be passed to the view via its ViewBag.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data.SqlClient;
using System.Threading;
using Microsoft.IdentityModel;
using Microsoft.IdentityModel.Claims;

namespace html5_mvc_razor.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        [ValidateInput(false)]
        public ActionResult Index()
        {
            LoadClaims();
            LoadPromos();
            return View();
        }

        private void LoadClaims()
        {
            ViewBag.Welcome = "Welcome Back!";
            var principal = Thread.CurrentPrincipal;
            var identity = principal.Identity as IClaimsIdentity;
            var claims = identity.Claims;
            ViewBag.Claims = claims;

            string displayName = null;

            if (claims != null)
            {
                string claimType;
                foreach (Claim claim in claims)
                {
                    claimType = claim.ClaimType;
                    if (claimType.EndsWith("/nameidentifier"))
                    {
                        displayName = claim.Subject.Name;
                        break;
                    }
                }
                if (!String.IsNullOrEmpty(displayName))
                {
                    ViewBag.Welcome = "Welcome back, " + displayName;
                }
            }
        }

        private void LoadPromos()
        {
            ...
        }

    }

    ...
}

<nav>
    @(ViewBag.Welcome)
 <a href="">Home</a>
 <a href="Map">Walking Map</a>
 <a href="#">About Us</a>
</nav>

Testing Authentication
Now it's time to see it work. When we run the solution (with F5 out of Visual Studio), we see a sign-in screen. That's because the application realized it did not have a security token and redirected us to the Access Control Service for sign-in. The sign-in screen requires the user to select an identity provider, after which the user will sign in with that provider.

Once we successfully sign in with an identity provider, we are redirected back to the application which is now happy because it sees a security token this time. We can see the display name claim is being retrieved via the "Welcome back, " message on the web page.

Summary
In Step 5 we secured the site by authenticating web identities using the Windows Azure Access Control Service. Our site now has the following functionality:

• Uses HTML5 and open standards on the web client
• Embodies responsive web design and runs on desktops, tablets, and phones.
• Provides server-side dynamic content (promotional items)
• Provides client-side dynamic content (Bing Maps)
• Is set up for Windows Azure Compute
• Can authenticate against web identities

In the next step, we'll deploy the application to a Windows Azure data center.

Mobile & Global with HTML5, MVC & Windows Azure, Step 4: Cloud-Ready

In this series of posts we’re progressively demonstrating a mobile and global sample, Responsive Tours. The source code for all 7 steps is on CodePlex at http://responsivetours.codeplex.com.

Here in Step 4 of 7 we’re going to make the project ready for cloud computing with Windows Azure. For the time being we are still going to be running the project locally on our development machine, using the Windows Azure Simulation Environment. In this step we will:

• Add a Windows Azure project to the solution
• Configure the MVC project as a Windows Azure web role
• Run the solution in the Windows Azure Simulation Environment


For this step and successive steps you need the Windows Azure Tools for Visual Studio & SDK version 1.6.

Adding a Windows Azure Project to the Solution

To make the solution runnable in Windows Azure we must add a Windows Azure project to it that contains metadata describing the solution’s shape and runtime requirements. We can do this easily by right-clicking the solution in Visual Studio Solution Explorer and selecting Add Windows Azure Deployment Project.

This action adds a new ResponsiveSite.Azure project to the solution and makes it the start-up project.
Configuring a Web Role

Windows Azure solutions consist of one or more roles. A role is like a tier of a solution, and there are several varieties. In this case we want to let the Windows Azure project know that our solution has a Web Role, and that the ResponsiveSite (MVC) project is that web role. All it takes to do this is to right-click the ResponsiveSite.Azure project’s Roles folder and select Associate With > Web Role Project in Solution. The ResponsiveSite project now appears under the Roles folder as shown below.

Configuring Instances
The metadata files in the Windows Azure project allow us to configure runtime information including the number of instances for each role. We’ll set the number of VM instances for our web role to 4 in ServiceConfiguration.Local.cscfg (used in the local simulator) and 2 in ServiecConfiguration.Cloud.cscfg (used in an actual deployment to a cloud data center). Note 2 is a minimum for high availability.

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="ResponsiveSite.Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="1" osVersion="*">
  <Role name="ResponsiveSite">
    <Instances count="4" />
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

Running the Solution in the Windows Azure Simulation Environment

We’re now ready to run the solution in the Windows Azure Simulation Environment, a feature that allows local development and testing of cloud solutions. Press F5 in Visual Studio, wait for the simulation environment to initialize, and note the solution starts up as usual.
One clue that you’re running a little differently under the hood is the web address you’ll see in the browser: 127.0.0.1:81. To get a better sense for what’s happening, we can use the Compute Emulator UI that is part of Windows Azure Simulation Environment. To do so, right-click the blue Windows Azure icon in your system tray (bottom right on the Windows desktop) and select Show Compute Emulator UI. You’ll soon see a display like the one below showing each of the VM ‘instances’ running (in the simulator, they are processes).


We won’t be deploying to the public cloud for a few more steps, but we’re set up for cloud hosting at this point with the Windows Azure Compute Service. When we do deploy to the cloud, we’ll also move our SQL Server database to a SQL Azure database in the cloud.
Summary

In Step 4 we made the solution ready for Windows Azure by adding a Windows Azure project, declaring the web project a web role, and configuring instances. Our site now has the following functionality:

• Uses HTML5 and open standards on the web client

• Embodies responsive web design and runs on desktops, tablets, and phones.
• Provides server-side dynamic content (promotional items)
• Provides client-side dynamic content (Bing Maps)
• Is set up for Windows Azure Compute
In the next step, we'll secure the application for sign-in with a web/social identity.

Mobile & Global with HTML5, MVC & Windows Azure, Step 3: Dynamic Content

In this series of posts we’re progressively demonstrating a mobile and global sample, Responsive Tours. The source code for all 7 steps is on CodePlex at http://responsivetours.codeplex.com.

Here in Step 3 of 7 we’re going to implement some dynamic content for the site—specifically, dynamic promotional item content and map integration. In this step we will add:

• Server-side dynamic content for promotional items driven by a database
• Client-side dynamic content for Bing Maps integration using device current location


Server-side Dynamic Content for Promotional Items

The bottom area of our web pages is for promotional items. There is room for three items each with an image, title, and description. We would like all of this to be dynamic so that new offers can be easily advertised.

There are several ways we might store content (database, primitive storage, content management system). In this case we’ll use a SQL Server database for the content and create a Promotions table that holds the image URL, title, and description for each promotional item. We add a database project to the solution for this purpose. We define three records of promotional content.

Now that we have this data, we need to implement retrieving it in our web project on the server side. The right place to do that is in our MVC controllers, by querying our database table and storing a collection of Promo items in the ViewBag for our views.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data.SqlClient;

namespace html5_mvc_razor.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            LoadPromos();
            return View();
        }

        private void LoadPromos()
        {
            Dictionary<string, Promo> Promos = new Dictionary<string, Promo>();

            try
            {
                using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Tours"].ConnectionString))
                {
                    conn.Open();

                    using (SqlCommand cmd = new SqlCommand("SELECT * FROM Promotions ORDER BY Id", conn))
                    {
                        using (SqlDataReader reader = cmd.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                Promos.Add(Convert.ToString(reader["Id"]), new Promo
                                    {
                                        Title = Convert.ToString(reader["Title"]),
                                        Text = Convert.ToString(reader["Text"]),
                                        ImageURL = Convert.ToString(reader["ImageURL"])
                                    }
                                );
                            }
                        }
                    }
                    conn.Close();
                }
            }
            catch (SqlException)
            {
                // TODO: log exception
            }

            ViewBag.Promos = Promos;
        }

    }

    public class Promo
    {
        public string Title;
        public string Text;
        public string ImageURL;
    }
}

One way to set dynamic content in MVC is with Razor. We can set the image URLs based on what’s in the ViewBag using the @ syntax:
<!-- begin - homepage promos -->
<div class="home_promo_container">
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(images/@(ViewBag.Promos["1"].ImageURL));">
   <h2>...</h2>
   <p>...</p>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(images/@(ViewBag.Promos["2"].ImageURL));">
   <h2>...</h2>
   <p>...</p>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="home_promo">
  <div class="home_promo_content" style="background-image:url(images/@(ViewBag.Promos["3"].ImageURL));">
   <h2>...</h2>
   <p>...</p>
   <a class="button" href="#">Learn more &raquo;</a>
  </div>
 </div>
 <div class="clear_both"></div>
</div>


Of course the images aren’t really dynamic yet—they’re still static files that are part of our web project—but once we change that in a later step we have a way to indicate the URL dynamically from our database.

Now let’s look at a more modern and versatile way to pass dynamic content from an MVC web back end to an open standards web client: data binding with Knockout.js. The Knockout library lets us apply the Model-View-ViewModel pattern to JavaScript. To do this, we need to:

• Use Razor to generate JavaScript code to create a ViewModel (JavaScript object) with content.

• Annotate HTML DOM elements with data-bind attributes to denote where data binding should occur.
• Initialize and call the Knockout library to apply data binding to the HTML.
You can see all three of these activities in the Home view page (Views/Home/Index.cshtml):


@{
    ViewBag.Title = "Responsive Tours";
}

@* Optional : Include additional stylesheets *@
@section StylesTop
{
<link rel="stylesheet" type="text/css" href="~/../css/stylesheet.css" />
<link rel="stylesheet" type="text/css" media="only screen and (min-width:50px) and (max-width:550px)"  href="~/../css/screen_small.css">
<link rel="stylesheet" type="text/css" media="only screen and (min-width:551px) and (max-width:800px)" href="~/../css/screen_medium.css">
<!--[if lt IE 9]>
 <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <link rel="stylesheet" type="text/css" href="~/../css/stylesheet_ie.css" />
<![endif]-->
}

@* Optional : Include additional immediately executed script references *@
@section ScriptsTop
{

}

@* Optional : Header content *@
@section Header
{
<meta name="description" content="This site was created from a template originally designed and developed by Codify Design Studio. Find more free templates at http://www.adobe.com/devnet/author_bios/chris_converse.html" />
<meta http-equiv="X-UA-Compatible" content="IE=9" />
}

@* Required : Render body container here *@
  <div class="page">
   <header><a class="logo" href="#"></a></header>
   <div class="page_content">

     
     <!-- begin - homepage promo -->
     <div class="marquee_container">
      <div class="marquee_photos"><br/><br/>loading...</div>
      <div class="marquee_caption">
       <div class="marquee_caption_content"></div>
       
      </div>
      <div class="marquee_nav"></div>
      <div class="marquee_panel_data"></div>
     </div>
     <div class="marquee_smallscreen"><br/><br/>loading...</div>
     <!-- end - homepage promo -->
     
     <!-- begin - homepage promos -->
     <div class="home_promo_container">
      <div class="home_promo">
       <div class="home_promo_content" style="background-image:url(images/@(ViewBag.Promos["1"].ImageURL));">
        <h2 data-bind="text: PromoTitle1"></h2>
        <p  data-bind="text: PromoText1"/>
        <a class="button" href="#">Learn more &raquo;</a>
       </div>
      </div>
      <div class="home_promo">
       <div class="home_promo_content" style="background-image:url(images/@(ViewBag.Promos["2"].ImageURL));">
        <h2 data-bind="text: PromoTitle2"></h2>
        <p  data-bind="text: PromoText2"/>
        <a class="button" href="#">Learn more &raquo;</a>
       </div>
      </div>
      <div class="home_promo">
       <div class="home_promo_content" style="background-image:url(images/@(ViewBag.Promos["3"].ImageURL));">
        <h2 data-bind="text: PromoTitle3"></h2>
        <p  data-bind="text: PromoText3"/>
        <a class="button" href="#">Learn more &raquo;</a>
       </div>
      </div>
      <div class="clear_both"></div>
      <!-- begin - homepage promos -->


    </div>
    <nav>
     <a href="">Home</a>
     <a href="Map">Walking Map</a>
     <a href="#">About Us</a>
    </nav>
   </div>
   <footer>&copy; 2011 &bull; Responsive Tours (a fictitious company)</footer>
  </div>

@* Optional : Include fooder content *@
@section Footer
{
}

@* Optional : Include additional deferred script references, or page initialisation *@
@section ScriptsBottom
{
<script type="text/javascript" src="~/../scripts/farinspace/jquery.imgpreload.min.js"></script>
<script type="text/javascript" src="~/../scripts/farinspace/template.js"></script>
<script type="text/javascript">
    var timeToChange = 6;     //seconds
    var transitionTime = 1.5; //seconds
</script>
<script>
$(document).ready(function () {

    // Knockout view model.
        
    var viewModel = {
        PromoTitle1: "@(ViewBag.Promos["1"].Title)",
        PromoTitle2: "@(ViewBag.Promos["2"].Title)",
        PromoTitle3: "@(ViewBag.Promos["3"].Title)",
        PromoText1: "@(ViewBag.Promos["1"].Text)",
        PromoText2: "@(ViewBag.Promos["2"].Text)",
        PromoText3: "@(ViewBag.Promos["3"].Text)"
    };

    // Activates knockout.js
    ko.applyBindings(viewModel);
});
</script>
<!-- Knockout data binding -->
<script type="text/javascript" src="~/../scripts/libs/knockout-1.2.1.min.js"></script>
}

With all of this in place, when we run the project we now see the promotional item content is loaded from the database on the server side and bound to the web page on the client side. Voila! -- dynamic content.
Client-side Map Integration
The other area of dynamic content is the map view. When a user clicks the Walking Map link, they are supposed to get an interactive map that is initially centered on their current location. This is an integration we can handle on the client side. We’ll do it using Bing Maps and HTML5’s geolocation feature.

With a Bing Maps key in hand, a small amount of JavaScript is all that is needed to render an interactive map, obtain the current location (if the user grants it), and center a map on that point. The code selects one of two map elements (“map1” or “map2”) based on which is visible for thr active device layout.
<!-- Bing Maps -->
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
    var map = null;

    function getMap() {

        var mapOptions = {
            credentials: 'PucpG1...BING-MAPS-KEY...ByFfkTmeGP',
            mapTypeId: Microsoft.Maps.MapTypeId.automatic,
            zoom: 17
        }

        var mapElement = document.getElementById("map1");
        if (!isVisible(mapElement)) {
            mapElement = document.getElementById("map2");
        }
        map = new Microsoft.Maps.Map(mapElement, mapOptions);
    }

    function setMapZoom(zoomLevel) {
        map.setView({ zoom: zoomLevel });
    }

    function getCurrentLocation() {
        var geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);
        geoLocationProvider.getCurrentPosition({ errorCallback: errorCallback, successCallback: displayCenter });
    }

    function displayCenter(args) {
        setMapZoom(17);
    }

    function errorCallback(object) {
        alert('Error callback invoked, error code ' + object.errorCode);
    }

    function isVisible(obj) {
        if (obj == document) return true

        if (!obj) return false
        if (!obj.parentNode) return false
        if (obj.style) {
            if (obj.style.display == 'none') return false
            if (obj.style.visibility == 'hidden') return false
        }

        //Try the computed style in a standard way
        if (window.getComputedStyle) {
            var style = window.getComputedStyle(obj, "")
            if (style.display == 'none') return false
            if (style.visibility == 'hidden') return false
        }

        //Or get the computed style using IE's silly proprietary way
        var style = obj.currentStyle
        if (style) {
            if (style['display'] == 'none') return false
            if (style['visibility'] == 'hidden') return false
        }

        return isVisible(obj.parentNode)
    }
</script>
When we run the project, select the map view, and give permission to use our location we are greeted with an interactive map initially showing our current location. We can use this in a walking tour of a city to see where we are, find points of interest, bookmark favorite spots, and find others in our party.



The final result of all this integration is a web site that has both client-side and server-side dynamic content: an interactive map for walking tours, and promotional items that can be easily changed via a database.
Summary
In Step 3 we enabled server-side dynamic content for promotional items using a database, MVC Razor, and Knockout. We also enabled client-side dynamic content via Bing Maps. Our site now has the following functionality:
• Uses HTML5 and open standards on the web client
• Embodies responsive web design and runs on desktops, tablets, and phones.
• Provides server-side dynamic content (promotional items)
• Provides client-side dynamic content (Bing Maps)

In the next step, we'll prepare the application for cloud computing on Windows Azure.