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):
<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:
<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.