RW

How to Use ASP.NET Membership in Azure

Published: 2014-02-08 | By: Ryan Williams

Problem

When using Windows Azure, I recently noticed strange behavior with the membership provider with SQL Azure. The application is deployed to many different environments (dev, staging, prod) and was previously using the same database for membershp in all environments. That connection string was set in the Web.config and was not in the .cscfg files.

When the requirement came up to have different membership databases, one for each environment, I thought all I needed to do was copy the existing database and update the .csdef and .cscfg to use the membership connection string. Unfortunately the portal was showing the wrong information, it was showing the connection string I wanted to use but the application was actually using the one set in the Web.config. 

Because of this strange behavior, integration tests were failing. I thought there was some problem with the way the machine key and the password was being validated. When I looked further, the call to authenticate a user was returning the message: Could not determine storage version; a valid storage connection or a version hint is required.

Solution

It turns out that the Web Role, this is using a Cloud Service, needs to update the connection string for the membership provider when it starts up. One of my co-workers pointed me to these 2 resources: Moving database connection string to Azure service configuration and ASP.NET Universal Providers + Azure cscfg

What this meant was that I needed the Web Role to change the Web.config in the OnStart method. So I put the connection string in the Web.config (as a place holder and for running without Azure), the .csdef and the .cscfg for each environment, with each .cscfg using its own database for membership.

The steps to fix were:

  • Put a default connection string in the Web.config
  • Update the .csdef with the connection string name.
  • Modify all .cscfg files to use the connection string name and value (the database I want for membership in that environment).
  • Change the connection string in the application during the OnStart event for the Work Role by modifying the WebRole.cs file in the web project. 

The end result is:

        private void SetMembershipConnectionString()
        {
            const string membershipDatabaseConnectionName = "MyMembershipConnectionString";
            var connectionStringCscfg = RoleEnvironment.GetConfigurationSettingValue(membershipDatabaseConnectionName);
           
            using (var server = new ServerManager())
            {
                const string siteNameFromServiceModel = "Web"; // this value is from: ServiceDefinition/WebRole/Sites=name
                var siteName = string.Format("{0}_{1}", RoleEnvironment.CurrentRoleInstance.Id, siteNameFromServiceModel);
                var siteConfig = server.Sites[siteName].GetWebConfiguration();
                var connectionStringsWebConfig = siteConfig.GetSection("connectionStrings").GetCollection();

                foreach (var connectionString in connectionStringsWebConfig)                                                
                {
                    if (connectionString.Attributes["name"].Value.ToString() == membershipDatabaseConnectionName)
                    {
                        connectionString.Attributes["connectionString"].Value = connectionStringCscfg;
                        break;
                    }
                }

                server.CommitChanges();
            }
        }

This gets called in the OnStart method by using the code below. This is because using IIS express it isn't needed. Locally, I never saw the problem anyway, only in Azure. To see this happen locally you need to change the Azure project to use the full IIS and to ignore the emulated part. 

if (RoleEnvironment.IsAvailable && !RoleEnvironment.IsEmulated)
{
    SetMembershipConnectionString();
}

Automation

If you want to use the command line to make a membership database with SQL Azure, you cannot use the typical way, you need to use a special Azure specific command accessible with: aspnet_regsqlazure.zip.

To run that command in PowerShell to create membership and roles you would do:


$aspnetRegSQLEXE = "PATH_TO\aspnet_regsqlazure.exe"
        
& $aspnetRegSQLEXE -S "SERVER" -U "USERNAME" -P "PASSWORD" -d "DATABASENAME" -A mr



No Comments... Yet


Comment On

Prove you are human 12 + 4 =