Since Scott Hanselman introduced the ASP.NET Universal Providers last year we learned that these providers should be used when working with SQL Azure. Version 1.2 of the providers were released just a few days ago, but this version still assumes you store your settings in the web.config.
When you’re building Cloud Services in Windows Azure you probably want to store this information in the ServiceConfiguration.cscfg. Since Visual Studio allows you to manage multiple configurations, you could store a connection string for local development, for a ‘beta’ environment, production, … But the ASP.NET Universal Providers don’t support this out of the box.
Getting around this limitation is pretty simply. We can intercept the initialization of these providers and to the necessary work so that they get the connection string configured in the ServiceConfiguration.cscfg.
Let’s take a look at how you would configure the ASP.NET Universal Providers with the web.config. First you need to add the package to your project:
After adding the package you can simply add the providers to the web.config:
Each provider has an attribute connectionStringName which specifies the name of the connection string that should be used. And that’s it. You providers are now working with a connection string specified in the web.config.
Using the ServiceConfiguration.cscfg
Instead of reading the connection string from the web.config we want to be able to use a connection string stored in the ServiceConfiguration.cscfg. After double clicking the Web Role in the Cloud project, the Settings tab makes it possible to add the connection string (and the ProviderName) to the Service Configuration:
I also added the Provider Name which we’ll need later (this is required by Entity Framework). In order to use this setting instead of the connection string in the web.config we simply override the Initialize method of the ProviderBase base class. Take the DefaultMembershipProvider for example, this is how we would override its Initialization method:
The config collection allows us to read the attributes which were specified in the web.config. The following example configures the AzureMembershipProvider as default membership provider with the connectionStringName set to UserDbConnectionString:
During the initialization of our custom membership provider we’ll have access to the connectionStringName configured for that provider (in this case UserDbConnectionString). The interception point is ready and the only thing left to do is read the connection string from the Service Configuration and make sure this connection string is used by the AzureMembershipProvider. I created a small helper class to make things easier:
The first method, GetRoleEnvironmentSetting, makes it easy to read the ServiceConfiguration and will throw a clear exception if the setting is not found. This will be used to read the connection string and the provider name.
The ASP.NET Universal Providers are thightly coupled to the ConfigurationManager.ConnectionStrings property, so there’s no way around this. The only solution would be to add the connection string at runtime whenever we initialize the provider. But if you ever tried to update the connection strings in a running application you’ll know that this collection is read-only. The SetConnectionStringsReadOnly method allows us to change the ConnectionStrings property from read-only to writable, and this is exactly what we need to inject our connection string coming from the Service Configuration.
Finally the UpdateConnectionString method makes sure the ConnectionStrings property is writeable, adds or updates the connection string and changes the ConnectionStrings property back to read-only. This helper class is used when overriding the Initialize method of the provider, which makes that method very light:
In order to use these providers you can simply delete the connection string from the web.config, add it to the Service Configuration and update the provider types in the web.config. Note that, when adding the connection string in the Service Configuration, you’ll need to add a setting with the same name and a “ProviderName” suffix to define the provider name (like System.Data.SqlClient).
The source for this sample application is available on GitHub.