June 28, 2010 | In: .Net, Asp.Net

Using dynamic connection strings with the Asp.Net Sql Membership Provider

So you did it.  You drank the MS Kool Aid and decided to go full bore and implement the Asp.Net Membership Provider.

As with any out of the box solution like the membership provider there are alot of pro’s.  It gives you quite a bit out of the box:

  • Ready made db for storing users, passwords, roles and more
  • Login controls, forgot my password control, etc
  • Lots of API classes to wrap users, roles, etc right out of the box
  • Highly configurable

Sounds great right?  Now say you’re like alot of developers I know and you have one database for development, possibly localhost.  You probably also have a staging or QA environment where your testers can create 100 users and try to break everything.  Then you have production – the real deal.

You’ve decided to use the Sql Membership Provider, you right all your code hitting your localhost db.  Everything runs perfect.  All your unit tests pass.  (You’re writing unit tests right?)  Now the move to QA.  Well step 1 is to create the Membership database on QA.  Ok, let’s a assume you can do this or can get a DBA to do this.

Now what?  All your connection strings point to localhost.  You look at your web.config and ugh – it looks like this:

<connectionStrings>
  <add name="MySqlConnection"   connectionString="Data Source=localhost;  Initial Catalog=aspnetdb;Integrated Security=SSPI;" />
</connectionStrings>
<system.web>
...
  <membership defaultProvider="SqlProvider">
    <providers>
      <clear />
      <add
        name="SqlProvider"
        type="System.Web.Security.SqlMembershipProvider"
        connectionStringName="MySqlConnection"
        applicationName="MyApplication"
        enablePasswordRetrieval="false"
        enablePasswordReset="true"
        requiresQuestionAndAnswer="true"
        requiresUniqueEmail="true"
        passwordFormat="Hashed" />
    </providers>
  </membership>

Ok, cool, I’ll just add a connection string for QA.  Wait, what’s this membership section?  You’re kidding right?  I can only have one connection string for my membership provider?  In short, the answer is yes, you can only have one.

So what’s the fix?

The solution is what I like to call complicated simple.  In theory it seems complicated.  In execution it’s actually pretty simple.  You can create your own membership provider and fix the little “bug”.

Create my own?  But doesn’t that defeat the whole purpose?  not exactly, you create your own, but inherit from all of Microsoft’s classes and only override one very small bit of functionality – the connection string implementation.

Your new Membership Provider:

public class MembershipProvider:SqlMembershipProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
 {
  base.Initialize(name, config);  

  // Update the private connection string field in the base class.
   var connectionString = IAmInQABool ? QAString : DevString;
 // Set private property of Membership provider.
  var connectionStringField = GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
 connectionStringField.SetValue(this, connectionString);
 	}
    }

Note: For the line where I set the connections string you’ll want to implement your own logic here.  Likely some sort of code to determine what system you’re running on and then grabbing the write connection string from your config file.

That’s it.  You’ve created your own Membership Provider.  Now all your really did was take everything MS was giving you by default and use a little reflection to override the connection string.  You new provider will work just like the old.  You can still use the login controls and all that good stuff.

The only last bit of config you’ll need is to update your web.config to not use the default membership provider but yours instead:

<membership defaultProvider="MembershipProvider">
	<providers>
	<clear/>
	<add name="MembershipProvider" type="MyFullNamespace.MembershipProvider, MyProject"          connectionStringName="ApplicationServices" enablePasswordRetrieval="true"          enablePasswordReset="true" requiresQuestionAndAnswer="false"          requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5"          minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0"          passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>
	</providers>
</membership>
<profile>
	<providers>
	<clear/>
	<add name="MembershipProvider" type="MyFullNamespace.MembershipProvider, ResellerDashboard"          connectionStringName="ApplicationServices" applicationName="/"/>
	</providers>
</profile>

That’s all there is to it.  Would love to hear if anyone reads this post and implements this solution.

11 Responses to Using dynamic connection strings with the Asp.Net Sql Membership Provider

Avatar

Brandon Dimperio

July 19th, 2010 at 4:07 am

Implemented, thanks a ton!

Avatar

Jason

August 20th, 2010 at 4:23 pm

When I tried implementing this solution and putting the code out to production (I’m using GoDaddy.com for hosting), then I get a security exception.

I contacted GoDaddy.com support… and they said basically tough luck, we can’t increase your privileges beyond the medium level. Which I guess that means I can’t use Reflection like in the example above…..

how sad.

Avatar

Jacob Nielsen

August 23rd, 2010 at 12:27 pm

Avatar

Jurgen

August 25th, 2010 at 2:28 pm

Worked like a charm. I spent ages looking for a good solution. Hope this gets fixed in the framework soon!

Avatar

Adrian Clark

September 6th, 2010 at 6:14 am

Wouldn’t the simpler solution to this be either having separate configuration files for separate environments?

If you don’t wish to duplicate ALL your settings use the “configSource” attribute and just externalise the “connectionStrings” element.

That way your Membership Provider always references “MySqlConnection” and just the contents of that section change.

Avatar

Brendan

September 24th, 2010 at 12:51 am

Maybe. Depends on your environment. If I want to publish my project anywhere anytime (like maybe on an Amazon EC2 machine) I don’t want to have to worry about which config file I need to be where.

Avatar

Mike

November 5th, 2010 at 12:21 pm

Wouldn’t this work better, as it does not rely on an internal property

public class CustomMembershipProvider : SqlMembershipProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
config["connectionStringName"] = // string here

base.Initialize(name, config);
}
}

Avatar

Tim

December 30th, 2010 at 6:15 am

Does anyone has this solution for VB.Net? I get the error bject variable or With block variable not set.

Avatar

Brendan

January 6th, 2011 at 3:48 pm

@Mike – I can’t see anything wrong with it at a glance, will have to try it out. Thanks!

@Tim – Should be straight forward. All the config stuff is exactly the same. Try using http://converter.telerik.com/ to convert the C# to VB.

Avatar

evilripper

June 21st, 2011 at 12:39 pm

thanks for the post and thanks to @Mike -> the best mode for me! :)

bye

Avatar

Tariq Razzaq

July 12th, 2011 at 4:44 pm

Whenever I do this, the base.initialise method fails saying it can’t find the ApplicationService connection string or that it is empty.

Is it possible to have all the connection string in the code and remove it from the web.config? I want to pull the connection string from the Role config in Azure

Comment Form