Exercise 1: Using the Azure ASP.NET Providers
In this exercise, you configure a sample shopping cart application implemented with ASP.NET Web Forms to run in Windows Azure and modify it to use the ASP.NET providers from the Windows Azure samples. You start by adding authentication to the site using the membership provider. Next, you implement the role provider to classify users and customize the products that the application offers. Finally, you configure the session state provider to store the contents of the shopping cart.
Task 1 – Configuring the Application to Run in Windows Azure
The Azure Store is a standard ASP.NET Web Forms sample that mimics a simple commerce application. It presents a list of products that users can select and add to their shopping cart.
Before you begin, you may wish to build and run the solution and become acquainted with its operation. In its initial state, the application runs outside the development fabric.
In this task, you create a Cloud Service project to configure the application to run in Windows Azure.
- Open Microsoft Visual Studio 2010 in elevated administrator mode, from Start | All Programs | Microsoft Visual Studio 2010 by right clicking the Microsoft Visual Studio 2010 shortcut and choosing Run as Administrator.
- If the User Account Control dialog appears, click Continue.
- In the File menu, choose Open and then Project/Solution. In the Open Project dialog, browse to Ex1-UsingAzureProviders\Begin in the Source folder of the lab, select Begin.sln in the folder for the language of your preference (Visual C# or Visual Basic) and click Open.
- Add a new Cloud project to the solution. In the File menu, point to Add and then select New Project.
In the Add New Project dialog, choose the Cloud category under Project types and then select Windows Azure Cloud Service from the list of installed templates. Set the name of the project to AzureStoreService, keep the proposed location in the solution folder and click OK.
Figure 1
Configuring the application to run as a Cloud Service
In the New Cloud Service Project dialog, click OK without adding new roles to the solution because you will use the existing application as a Web role.
Figure 2
Configuring roles in the cloud service project
Associate the ASP.NET Web Forms project to the cloud project. In Solution Explorer, right-click the Roles node in the AzureStoreService project, point to Add and select Web Role Project in solution.
Figure 3
Associating a Web Role project in the solution
In the Associate with Role Project dialog, select the WebFormAzureStore project and click OK.
Figure 4
Associating the Web Forms application as a Web Role project
When you associate a new role, Visual Studio updates the ServiceDefinition.csdef and the ServiceConfiguration.cscfg files. If either of these files is currently open, make sure that you save it to preserve these changes.
Add a reference to the assemblies required to support the Azure environment. In Solution Explorer, right-click the WebFormAzureStore project, select Add Reference, click the .NET tab, select the Microsoft.WindowsAzure.Diagnostics, Microsoft.WindowsAzure.ServiceRuntime, and Microsoft.WindowsAzure.StorageClient components and click OK.
Figure 5
Adding a reference to the Windows Azure components
Configure a TraceListener to enable diagnostics logging for the application. Open the Web.config file and insert a system.diagnostics section as shown below.<configuration>
...
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="AzureDiagnostics" type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
These settings in the system.diagnostics section configure a trace listener specific to Windows Azure that allows the application to trace code execution using the classes and methods available in the System.Diagnostics.Trace class.
This step is usually unnecessary for roles created in Visual Studio because they already include the necessary settings in their role templates.
- Add an entry point class to the Web role. In SolutionExplorer, right-click the WebFormAzureStore project, point to Add and select Class. In the AddNewItem dialog, set the Name to WebRole.cs (for Visual C# projects) or WebRole.vb for (Visual Basic projects) and click Add.
In the WebRole.cs or WebRole.vb file, declare the following namespaces.
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Azure Namespaces - C#)
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Azure Namespaces - VB)
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.Diagnostics
Imports Microsoft.WindowsAzure.ServiceRuntime
Update the declaration of the WebRole class to inherit the RoleEntryPoint class.namespace WebFormAzureStore
{
public class WebRole
: RoleEntryPoint
{
}
}
Public Class WebRole
Inherits RoleEntryPoint
End Class
Add an OnStart method to set up Windows Azure Diagnostics and initialize the configuration settings publisher.
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 WebRole OnStart - C#)
public override bool OnStart()
{
return base.OnStart();
}
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 WebRole OnStart - VB)
Public Overrides Function OnStart() As Boolean
Return MyBase.OnStart()
End Function
The WebRole class is the entry point of the role. It contains methods that Windows Azure calls at various stages during its lifetime.
Here, you override the OnStart method. Windows Azure invokes OnStart when the role starts. Typically, you use this method to execute initialization code for the application. Alternatively, web roles can place their initialization code in the ASP.NET Application_Start method.
In this case, the initialization code starts the diagnostic monitor to collect diagnostic data locally for the role instance. In addition, it sets up a publisher that enables configuration settings for Azure Storage to be retrieved from the service configuration file.
In the Global.asax file from the Web role, declare the following namespaces. using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.ServiceRuntime
Find the Application_Start method and initialize the configuration settings publisher.
(Code Snippet – Building MVC Applications with Windows Azure - Ex01 SetConfigurationSettingPublisher – C#)
void Application_Start(object sender, EventArgs e)
{
Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});
...
}
(Code Snippet – Building MVC Applications with Windows Azure - Ex01 SetConfigurationSettingPublisher - VB)
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
CloudStorageAccount.SetConfigurationSettingPublisher(Function(configName, configSetter) configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
...
End Sub
Task 2 – Configuring Authenticated Access to the Application
In this task, you configure the application to require authenticated access to the pages that implement the shopping cart.
Configure authorization for the Store folder to require authenticated access. Open the Web.config file of the WebFormAzureStore project and insert the following (highlighted) configuration block as a direct child of the <configuration> element.<?xml version="1.0"?>
<configuration>
...
<location path="Store">
<system.web>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
</system.web>
</location>
</configuration>
Set the authentication mode of the application. To do this, locate the <authentication> element within <system.web> and change its mode attribute to the value Forms. Within the <authentication> element, create a <forms> element and set the value of its loginUrl attribute to Account/Login.aspx, as shown below.
Figure 6
Configuring the authentication mode of the application
- Press CTRL + S to save the Web.config file.
Task 3 – Configuring Membership Support Using the Azure TableStorageMembershipProvider
In this task, you add and configure the Azure ASP.NET providers for membership, role, and session.
Add the Windows Azure ASP.NET Providers project to the solution. In Solution Explorer, right-click the Begin solution, point to Add and select Existing Project. Browse to Assets\AspProviders in the Source folder of the lab, select the AspProviders.csproj project and click Open.
The AspProviders project is available as a sample. It is included as part of this training kit for your convenience. You can find the original source code in the MSDN Code Gallery. The project contains the implementation of ASP.NET application providers for membership, role, profile, and session state.
Add a reference in the Web role to the AspProviders project. In SolutionExplorer, right-click the WebFormAzureStore project node and click AddReference. In the AddReference dialog, switch to the Projects node, select the AspProviders project and click OK.
Figure 7
Adding a reference to the sample Azure ASP.NET Providers project
- Update the service configuration to include a connection string to the Azure Storage account where the data will be stored. In the AzureStoreService project, expand the Roles nodes and double-click the WebFormAzureStore node to open the properties window for this role.
In the WebFormAzureStore[Role] properties window, select the Settings tab and click AddSetting. Set the Name of the new setting to DataConnectionString and change the Type to ConnectionString. Then, in the Value column, click the button labeled with an ellipsis.
Figure 8
Creating a new configuration setting for the role
In the StorageConnectionString dialog, choose the option labeled Usedevelopmentstorage and click OK.
Figure 9
Configuring a storage connection string
- Press CTRL + S to save your changes to the role configuration.
- Open the Web.config file of the WebFormAzureStore project.
(Optional) Configure the storage account information required by the ASP.NET providers in the application configuration file. To do this, locate the <appSettings> element, which should be empty, and replace it with the following configuration block. If the appSettings element is missing, insert it as a direct child of the <configuration> element.
In addition to the service configuration file, you can also configure the Azure providers in the Web.config file of the application. This allows you to host the application outside the Azure fabric and still take advantage of the Azure ASP.NET providers and Azure storage. However, when the application runs in the Windows Azure environment, configuration settings in the service configuration file for the Azure ASP.NET providers override those in the Web.config file. By using the Windows Azure settings, you can avoid repackaging the application when changing provider settings.
<?xml version="1.0"?>
<configuration>
...
<appSettings>
<add key="DataConnectionString" value="UseDevelopmentStorage=true"/>
</appSettings>
...
</configuration>
Configure the application to use the membership provider in the AspProviders project. To do this, insert the following (highlighted) configuration block as a direct child of the <system.web> element.<configuration>
...
<system.web>
...
<!-- Membership Provider Configuration -->
<membership defaultProvider="TableStorageMembershipProvider" userIsOnlineTimeWindow="20">
<providers>
<clear/>
<add name="TableStorageMembershipProvider"
type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageMembershipProvider"
description="Membership provider using table storage"
applicationName="WebFormAzureStore"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
minRequiredPasswordLength="1"
minRequiredNonalphanumericCharacters="0"
requiresUniqueEmail="true"
passwordFormat="Hashed"/>
</providers>
</membership>
</system.web>
...
</configuration>
Important: Before you execute the solution, make sure that the start up project is set and that a start up page has been designated.
To set the start up project, in Solution Explorer, right-click the AzureStoreService project and select Set as StartUp Project.
To designate a start page, in Solution Explorer, expand the Store folder in the WebFormsAzureStore project, right-click Products.aspx and select Set As Start Page.
Press F5 to build and run the application. An initialization procedure may be required the first time you execute an application that uses storage in your development environment. If this happens, wait until the procedure is complete and review its status. Click OK to continue.
Figure 10
Development storage initialization procedure status
Notice that the application redirects you to the log in page when it starts because the authorization settings now require authenticated access to the Store folder. The membership database is initially empty, so you first need to create an account before you can proceed. In the log in page, click Register to access the user registration form.
Figure 11
Log in form indicating that authentication is required to proceed
Fill in the registration form and click Create User to register your account.
Figure 12
Creating a new user account
After creating the account, the application displays a confirmation message. Click Continue to proceed to the products page.
Figure 13
Account successfully created
After successfully creating your account, the system automatically logs you in and displays the products page. Notice your user name displayed in the upper right corner of the window.
Figure 14
Products page displaying the current user
- Close the browser window to stop the running application.
Task 4 – Configuring Role Support Using the Azure TableStorageRoleProvider
In this task, you add role support to the application using the Azure role provider. This requires updating the registration process to capture the role of the user and configuring the settings for the role provider. To demonstrate the use of roles, you update the products page to filter the list of products based on the type of user.
Update the registration process to assign a role to the user. Open Register.aspx and insert the following (highlighted) markup to add a new step in the CreateUserWizard control.<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" EnableViewState="true" >
...
<WizardSteps>
<asp:WizardStep>
<div>Choose a customer profile:</div>
<asp:RadioButtonList ID="roles" runat="server"
RepeatDirection="Vertical"
RepeatLayout="Flow" CssClass="role" />
</asp:WizardStep>
<asp:CreateUserWizardStep ID="RegisterUserWizardStep" runat="server">
<ContentTemplate>
<h2>
Create a New Account
</h2>
<p>
Use the form below to create a new account.
</p>
...
Add an event handler for the event that fires when the wizard creates the user. Add an OnCreatedUser attribute to the CreateUserWizard control and set the name of the event handler to OnCreatedUser.<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" CssClass="login"
... OnCreatedUser="OnCreatedUser"
<WizardSteps>
In the Register.aspx.cs code-behind file, add the following code to define the OnCreatedUser event handler.
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 OnCreatedUser - C#)
protected void OnCreatedUser(object sender, EventArgs e)
{
var list = (RadioButtonList)this.CreateUserWizard1.WizardSteps[0].FindControl("roles");
System.Web.Security.Roles.AddUserToRole(
this.CreateUserWizard1.UserName,
list.SelectedItem.Text);
}
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 OnCreatedUser - VB)
Protected Sub OnCreatedUser()
Dim list = DirectCast(Me.CreateUserWizard1.WizardSteps(0).FindControl("roles"), RadioButtonList)
System.Web.Security.Roles.AddUserToRole(Me.CreateUserWizard1.UserName, list.SelectedItem.Text)
End Sub
The code retrieves the role selected in the wizard and then adds the user to this role using the configured role provider.
Insert the following code into the body of the Page_Load method to initialize the CreateUserWizard control using the roles defined by the application.
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Page_Load - C#)
protected void Page_Load(object sender, EventArgs e)
{
CreateUserWizard1.ContinueDestinationPageUrl = Request.QueryString["ReturnUrl"];
if (!IsPostBack)
{
var list = (RadioButtonList)this.CreateUserWizard1.WizardSteps[0].FindControl("roles");
list.DataSource = System.Web.Security.Roles.GetAllRoles().OrderByDescending(a => a);
list.DataBind();
if (list.Items.Count > 0)
{
list.Items[0].Selected = true;
}
}
}
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Page_Load - VB)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
CreateUserWizard1.ContinueDestinationPageUrl = Request.QueryString("ReturnUrl")
If (Not IsPostBack) Then
Dim list = DirectCast(Me.CreateUserWizard1.WizardSteps(0).FindControl("roles"), RadioButtonList)
list.DataSource = System.Web.Security.Roles.GetAllRoles().OrderByDescending(Function(a) a)
list.DataBind()
If list.Items.Count > 0 Then
list.Items(0).Selected = True
End If
End If
End Sub
Add code to the start-up routine to initialize the roles supported by the application. The code creates two roles, Home and Enterprise, which the application uses to classify different types of users. Open Global.asax.cs (for Visual C# projects) or Global.asax.vb (for Visual Basic projects) and insert the following (highlighted) code into the Application_Start method.
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Initialize Roles - C#)
protected void Application_Start()
{
Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});
LoadProducts();
// Initialize the application roles
if (!System.Web.Security.Roles.RoleExists("Home"))
{
System.Web.Security.Roles.CreateRole("Home");
}
if (!System.Web.Security.Roles.RoleExists("Enterprise"))
{
System.Web.Security.Roles.CreateRole("Enterprise");
}
}
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Initialize Roles - VB)
Sub Application_Start()
CloudStorageAccount.SetConfigurationSettingPublisher(Function(configName, configSetter) configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
LoadProducts()
' Initialize the application roles
If (Not System.Web.Security.Roles.RoleExists("Home")) Then
System.Web.Security.Roles.CreateRole("Home")
End If
If (Not System.Web.Security.Roles.RoleExists("Enterprise")) Then
System.Web.Security.Roles.CreateRole("Enterprise")
End If
End Sub
Although you could use the OnStart method of the web role to initialize the application roles, by using the ASP.NET Application_Start method the application remains host-environment agnostic and allows you to run the unmodified application outside Azure, leaving the OnStart method dedicated to Azure specific initialization.
Note that you may need to remove the DiagnosticMonitorTraceListener in the system.diagnostics section of the configuration file in order to run the application outside the Azure environment.
Change the product page to filter the list of products based on the type of user. Open the Products.aspx.cs code-behind file (for a Visual C# project) or the Products.aspx.vb code-behind file (for a Visual Basic project) in the Store folder and insert the following (highlighted) code into the Page_Init method, immediately below the line that declares and initializes the filteredProducts variable.
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Page_Init - C#)
protected void Page_Init(object sender, EventArgs e)
{
var products = this.Application["Products"] as List<string>;
var itemsInSession = this.Session["Cart"] as List<string> ?? new List<string>();
// add all products currently not in session
var filteredProducts = products.Where(item => !itemsInSession.Contains(item));
// Add additional filters here
// filter product list for home users
if (User.IsInRole("Home"))
{
filteredProducts = filteredProducts.Where(item => item.Contains("Home"));
}
foreach (var product in filteredProducts)
{
this.products.Items.Add(product);
}
}
(Code Snippet – Building Web Form Applications with Windows Azure - Ex01 Page_Init - VB)
Protected Sub Page_Init() Handles Me.Init
Dim products = TryCast(Me.Application("Products"), List(Of String))
Dim itemsInSession = If(TryCast(Me.Session("Cart"), List(Of String)), New List(Of String)())
' add all products currently not in session
Dim filteredProducts = products.Where(Function(item) (Not itemsInSession.Contains(item)))
' Add additional filters here
' filter product list for home users
If User.IsInRole("Home") Then
filteredProducts = filteredProducts.Where(Function(item) item.Contains("Home"))
End If
For Each product In filteredProducts
Me.products.Items.Add(product)
Next
End Sub
The inserted code appends an additional filter for users in the Home role that returns only items containing the text “Home”.
Configure the application to use the role provider in the AspProviders project. In the Web.config file, insert the following (highlighted) configuration block as a direct child of the <system.web> element.<configuration>
...
<system.web>
...
<!-- RoleManager Provider Configuration -->
<roleManager enabled="true"
defaultProvider="TableStorageRoleProvider"
cacheRolesInCookie="true"
cookieName=".ASPXROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
cookieProtection="All">
<providers>
<clear/>
<add name="TableStorageRoleProvider"
type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageRoleProvider"
description="Role provider using table storage"
applicationName="WebFormAzureStore" />
</providers>
</roleManager>
...
</system.web>
...
</configuration>
- Press F5 to build and run the application.
In the log in page, click Register to access the user registration form. Notice that the registration wizard now displays an additional step to input the type of customer. Create a new user and assign it a Home customer profile.
Figure 15
Registration page showing the new role assignment step
Logged in as a Home user, proceed to the products page. Notice that the list of products only includes home products.
Figure 16
Products page showing a filtered list of products based on role
- Click the Logout link in the upper left corner of the application window.
Register a new account and assign this user an Enterprise profile. Notice that the list of displayed products differs from that seen by a Home user.
Figure 17
Products page showing Enterprise products
- Select a product from the list and click Add item to cart. You may repeat the process to store additional items in the cart.
Click the Check Out link to view the contents of the shopping cart. Verify that the items you selected appear on the list.
Figure 18
Check out page showing the contents of the shopping cart
- Do not close the browser window or navigate away from the checkout page.
- In the task bar, right-click the compute emulator icon and select Show Compute Emulator UI.
In the Compute Emulator, right-click the AzureStoreService node and choose Suspend.
Figure 19
Suspending the service role instance
Open a command window in elevated administrator mode, from Start | All Programs | Accessories | Command Prompt by right clicking the Command Prompt shortcut and choosing Run as Administrator and type iisreset.
Figure 20
Executing iisreset command
These two steps, recycling the role and restarting IIS, simulate what would happen in the Windows Azure platform when a role instance is restarted.
- Go back to the Compute Emulator and wait until the service stops as indicated by the instance icon turning red. Now, restart the service instance once again. To do this, right-click the AzureStoreService node and choose Run, then wait for the service to start.
Switch back to the browser window showing the check out page and click Refresh. Notice that the order now appears empty.
The application is currently using inproc session state, which maintains all session state in-memory. When you stop the service instance, it discards all session state including the contents of the shopping cart. In the following task, you will configure the application to store session state in Azure storage, which allows the application to maintain session state in the presence of restarts and across multiple machines hosting the application.
- Close the browser window to stop the application.
Task 5 – Configuring Session Support Using the Azure TableStorageSessionProvider
Windows Azure can potentially host a Web role on multiple machines inside the fabric, which makes in-memory session state unsuitable for such an environment. In contrast, the session state provider in the AspProviders project uses table storage to store configuration information about the session and blob storage to store the session state itself.
In this task, you configure the application to use the Azure session state provider.
Configure the application to use the session provider in the AspProviders project. To do this, in the Web.config file of the WebFormAzureStore project, insert the following (highlighted) configuration block as an immediate child of the <system.web> element.<configuration>
...
<system.web>
...
<!-- SessionState Provider Configuration -->
<sessionState mode="Custom"
customProvider="TableStorageSessionStateProvider">
<providers>
<clear/>
<add name="TableStorageSessionStateProvider"
type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageSessionStateProvider"
applicationName="WebFormAzureStore" />
</providers>
</sessionState>
...
</system.web>
...
</configuration>
- Press F5 to build and run the application.
- Log in and navigate to the products page. Select one or more products from the list and click Add item to cart. Repeat the process to store additional items in the cart.
- Click the Check Out link to view the contents of the shopping cart. Verify that the items you selected appear on the list.
- Do not close the browser window or navigate away from the checkout page.
- In the task bar, right-click the compute emulator icon and select Show Compute EmulatorUI.
- In the Compute Emulator, right-click the AzureStoreService node and choose Suspend. Wait until the service stops as indicated by the instance icon turning red.
- Now, restart the service instance once again. To do this, right-click the AzureStoreService node and choose Run, then wait for the service to start.
- Switch back to the browser window showing the check out page and click Refresh. Notice that the order is intact. This confirms that the session state can persist through application restarts when using the Azure provider.
- Close the browser window to stop the application.
|
|