Common Gotcha: Don't forget to <clear/> when adding providers

Recently I've helped a few people out who were having an issue with how they had added new Membership, Role, and Profile providers within their web.config file.  If you are ever going to add a provider declaration within your web.config file, please read-on to learn how to avoid a common gotcha.

Symptom:

You want to configure ASP.NET 2.0 to store your Membership/Role Management/Profile data within a remote SQL database.  To accomplish this you first use the aspnet_regsql.exe utility to provision the appropriate schema within the database.  Rather than override the "LocalSqlServer" connection string within your web.config file, you decide to register a new provider within your web.config file like below (note: the following registration has a bug - so don't copy/paste it):

      <membership>

            
<providers>
                
<add name="AspNetSqlMembershipProvider"
                    type
="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                    connectionStringName
="MyDatabase"
                    enablePasswordRetrieval
="false"
                    enablePasswordReset
="true"
                    requiresQuestionAndAnswer
="true"
                    requiresUniqueEmail
="false"
                    passwordFormat
="Hashed"
                    maxInvalidPasswordAttempts
="5"
                    minRequiredPasswordLength
="7"
                    minRequiredNonalphanumericCharacters
="1"
                    passwordAttemptWindow
="10"
                    passwordStrengthRegularExpression
="" 
                    applicationName
="/" 
                
/>
            </
providers>

      
</membership>

When registering the above provider you are careful to explictly set the applicationName property, and so avoid another really common gotcha.

When you run your application on a machine without SQL Express, though, you see some weird behavior.  You might get a SQL error like so:

An error has occurred while establishing a connection to the server.  When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

You might also find that the web administration tool has problems connecting with your database and/or the roles/users you create within it aren't correctly saved in the database you configured above.

Cause of the Problem:

The root cause of the above problem rests in how the new provider was registered within the web.config file. 

The <providers> section within the web.config file is implemented as a collection, and so it is possible to register multiple providers at the same time (this is useful when you want to have some users authenticated using one Membership store, and others authenticated using a separate Membership store).

By default ASP.NET 2.0 registers a set of default SQL Express providers within the root web.config file on your machine that create a SQL Express database within your /app_data directory to store/manage membership/role/profile data when you first access it.  Because this is registered at the machine-wide level, all provider collections by default inherit this registration.  Unless you explictly <clear/> or override the inherited value, your application will have this default membership/role/profile provider registered.

Because the above web.config file simply added a new provider -- and didn't clear or replace the default provider registration -- the above application now has two Membership providers configured.  When you do a Membership.CreateUser() call in your code, ASP.NET will attempt to create the user in both membership databases.  If you don't have SQL Express installed on your system, the create-user attempt will fail for this database - which leads to the errors and/or weird behavior above.

How to Fix It:

Unless you wish to register multiple membership, role or profile databases (which is rare), you should always add an explicit <clear/> directive before your <add/> statements within your web.config file:

      <membership>

            
<providers>
                
<clear/>
                
<add name="AspNetSqlMembershipProvider"
                    type
="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                    connectionStringName
="MyDatabase"
                    enablePasswordRetrieval
="false"
                    enablePasswordReset
="true"
                    requiresQuestionAndAnswer
="true"
                    requiresUniqueEmail
="false"
                    passwordFormat
="Hashed"
                    maxInvalidPasswordAttempts
="5"
                    minRequiredPasswordLength
="7"
                    minRequiredNonalphanumericCharacters
="1"
                    passwordAttemptWindow
="10"
                    passwordStrengthRegularExpression
="" 
                    applicationName
="/" 
                
/>
            </
providers>

      
</membership>

This will ensure that your application doesn't inherit any default provider registrations. 

Note that you must do this for each provider declaration that you register.  So if you are adding providers for <roles> and <profile>, make sure you add the <clear/> directive in their providers section as well.

Hope this helps,

Scott

P.S. Click here to review other past ASP.NET Tips/Tricks, Gotchas, and Recipes.

13 Comments

  • hmm I had a big problem when I used this with out application but later understood the system and updated it, Good trick

  • Good post Scott, this has caught me out before. Kirk

  • Wow, that helps a lot. I was messing with a custom Membership provider in a remote database a while back. I wasn't getting the error you describe, but I was seeing bizarre behavior that I was unable to explain. I ended up making some changes in the application that I didn't want in order to make the system work as expected. It makes perfect sense that the bizarre behavior was coming from the default provider.

    Thanks Scott.

  • Awesome - thanks Brennan!

    Scott

  • What's the difference between using the remove and the clear property? Should I use remove, or clear?

    Thanks.

  • Hi Webdroid,

    You can use the directive to remove a specific provider. removes all of them.

    You can use the same approach with just a single directive if you want. I generally recommend using just because it ensures that you remove all of them.

    Thanks,

    Scott

  • I finished discovering in practises, but now I am understanding better with its explanation.

    thanks,

    Ramon

  • Great timely gotcha... I was scratching my head over just this very issue earlier today :-)

  • Why this method is prefered, rather then overriding the "LocalSqlServer" ?

    Thanks

  • Scott,

    I am curious about an aspect which this configuration makes possible. I know you can have more than 1 provider active, such as an XML in addition to a SQL provider. Do you know any examples of this being done? I have been kicking this around in the back of my head the past few weeks.

    In one scenario you may have a mix of different user accounts and based on the user you may work with a different provider, such as LDAP, AD, or SQL. I am interested in real world examples of this approach.

  • last month i switched hostings because of this!

  • Hi Brennan,

    I'll put it on my list of things to blog about (warning - the list is long so I'm not 100% sure when I'll get to it!)

    In a nutshell, you can control which provider is the "default" provider by setting the "defaultProvider" property that is on the , , elements in web.config.

    Programmatically you can the choose a different provider by accessing the "Providers" collection on the Membership/Roles API. For example:

    Membership.Providers["otherprovider"].ValidateUser(username,
    password)

    Note that the "otherprovider" name is determined by the element in your web.config file (where you give each provider a name).

    Hope this helps,

    Scott

  • Hi Petr,

    Simply overriding the "LocalSqlServer" connection-string also works. The one benefit of redefining the provider is you can also go ahead and change any of the provider properties at the same time.

    Hope this helps,

    Scott

Comments have been disabled for this content.