ASP.NET Universal Providers

Last update: 15 August 2012

The SqlMembershipProvider, SqlRoleProvider, SqlProfileProvider classes that shipped in ASP.NET through version 4 support only Microsoft SQL Server and Microsoft SQL Server Express. They do not support newer offerings such as Microsoft SQL Azure and Microsoft SQL Server Compact.

ASP.NET Universal Providers have been created in order to extend support to all editions of SQL Server 2005 and later and to SQL Azure. If you use these providers to develop your application, the application will be ready for cloud environments like Azure.

Other than supporting additional storage options, the providers work like the existing SQL-based providers. Except as noted below, using ASP.NET Universal Providers requires no change in any of your applications.

Installing and Configuring ASP.NET Universal Providers

To install ASP.NET Universal Providers, you use a NuGet package, which installs all required files (including this documentation). The NuGet package automatically enables the new providers when it is installed. By default, the NuGet package configures provider to use SQL Server Express. To use SQL Server Compact or SQL Azure, you must change the connection string for the provider, as explained later in this document.

To enable the providers, the NuGet package adds configuration entries in the web.config file. The configuration for these providers is the same as the existing SqlMembershipProvider class, but the type parameter is set to the type of the new providers, as shown in the following table:

SQL Provider Types Equivalent Type for Universal Providers
System.Web.Security.SqlMembershipProvider System.Web.Providers.DefaultMembershipProvider
System.Web.Profile.SqlProfileProvider System.Web.Providers.DefaultProfileProvider
System.Web.Security.SqlRoleProvider System.Web.Providers.DefaultRoleProvider
(Built into default provider) System.Web.Providers.DefaultSessionStateProvider

In the web.config file, the configuration looks like the following example (the connection string has been wrapped for readability). The differences from the configuration for older SQL-based providers are highlighted. Notice that a section has been added to define custom session-state handling using a custom provider, as described later under Storing Data in Session State using ASP.NET Universal Providers.

<configuration>
<connectionStrings>
  <add name="DefaultConnection"
    connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=aspnetdb;Integrated Security=True"
    providerName="System.Data.SqlClient" />
  </connectionStrings>

  <system.web>
    <membership defaultProvider="DefaultMembershipProvider">
      <providers>
        <clear />
        <add name="DefaultMembershipProvider"
             type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
             connectionStringName="DefaultConnection"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="false"
             requiresUniqueEmail="false"
             maxInvalidPasswordAttempts="5"
             minRequiredPasswordLength="6"
             minRequiredNonalphanumericCharacters="0"
             passwordAttemptWindow="10"
             applicationName="/" />
      </providers>
    </membership>

    <profile defaultProvider="DefaultProfileProvider">
      <providers>
        <clear />
        <add name="DefaultProfileProvider"
             type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
             connectionStringName="DefaultConnection"
             applicationName="/" />
      </providers>
    </profile>

    <roleManager defaultProvider="DefaultRoleProvider" enabled="false">
      <providers>
        <clear />
        <add name="DefaultRoleProvider"
             type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
             connectionStringName="DefaultConnection"
             applicationName="/" />
      </providers>
    </roleManager>

    <sessionState mode="Custom" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider"
           type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           connectionStringName="DefaultConnection"
           applicationName="/" />
      </providers>
    </sessionState>
  </system.web> 

Selecting a Data Store

If you want to use SQL Server LocalDB database,change the connection string as shown in the following example:

<connectionStrings>
  <add name="DefaultConnection" providerName="System.Data.SqlClient" 
connectionString="Data Source=(LocalDb)\v11.0;
Initial Catalog=aspnet-ProjectName-GUID;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|\aspnet-ProjectName-GUID.mdf" />
<connectionStrings>

If you want to use SQL Server Express database,change the connection string as shown in the following example:

<connectionStrings>
  <add name="DefaultConnection" providerName="System.Data.SqlClient" 
connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=aspnetdb;
    Integrated Security=True" providerName="System.Data.SqlClient"/>
<connectionStrings>

If you want to use SQL Server Compact, change the connection string as shown in the following example:

<connectionStrings>
  <add name="DefaultConnection" connectionString="Data Source=|DataDirectory|\aspnet.sdf" 
      providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>

If you want to use SQL Azure, change the connection string as shown in the following example (wrapped for readability):

<connectionStrings>
  <add name="DefaultConnection" 
     connectionString="data source=myDNSName;
         User ID=myUserName;Password=myPassword;
         Encrypt=true;Trusted_Connection=false=false"
     providerName="System.Data.SqlClient"/>
<connectionStrings>

Storing Data in Session State using ASP.NET Universal Providers

By default, ASP.NET stores session data using an in-process (in-memory) session provider. This provider allows you to put any object in session state, because session state simply holds a reference to the object, not the object itself.

However, cloud environments might run your application on multiple computers. Therefore, for cloud-based applications, the application must store session state in some form of storage (like a database) that be accessed by more than one machine. This puts some restrictions on what data you store in session state — essentially, the data must be serializable.

When you install ASP.NET Universal Providers, the installation process configures session state to use the System.Web.Providers.DefaultSessionStateProvider type, as shown in the web.config file example earlier. This type stores session state in a database.

Session data must be serializable. If you attempt to store something in session state that is not serializable, you will receive the following error:

Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. the same restriction applies if similar serialization is done by the custom session state store in 'Custom' mode.

There are two ways to resolve this issue: by marking the type as serializable or by using a surrogate serializer.

Marking Types as Serializable

If you have access to the source code for the type that is being stored in session state, you can mark the type using the Serializable attribute, as in the following example. If the type contains additional classes, all the contained classes must be serializable as well.

[Serializable]
public class Address { }

[Serializable]
public class Person { 
     public Address Work;
     public Address Home; 
}

Using a Surrogate Serializer in .NET Framework 4.5

If it's not practical to mark the type as serializable in source code, and if you are using .NET Framework 4.5, you can use a surrogate serializer. (This technique does not work in .NET Framework 4.)

Create a class that implements the ISerializationSurrogate interface. In this class, you implement GetObjectData and SetObjectData methods in order to serialize and deserialze the data, respectively. In GetObjectData you invoke SerializationInfo.AddValue (using the appropriate overload for the data type of your data) to add individual fields of the object to serialize to a SerializationInfo object. In SetObjectData you extract the serialized version back to its original value in the object. Here's an example:

public class EmployeeSerializationSurrogate : ISerializationSurrogate
{
    // Serialize the Employee object to save the object name and address fields.
    public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context)
    {
        Employee emp = (Employee)obj;
        info.AddValue("name", emp.name);
        info.AddValue("address", emp.address);
    }

    // Deserialize the Employee object to set the object name and address fields.
    public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context,
        ISurrogateSelector selector)
    {
        Employee emp = (Employee)obj;
        emp.name = info.GetString("name");
        emp.address = info.GetString("address");
        return null;
    }
}

You then register the serializer and the class to be serialized using the SurrogateSelector class in code, like this:

protected void Page_Load(object sender, EventArgs e)
{
    SurrogateSelector ss = new SurrogateSelector();
    ss.AddSurrogate(typeof(Employee), new StreamingContext(StreamingContextStates.All), new EmployeeSerializationSurrogate());
    SessionStateUtility.SerializationSurrogateSelector = ss;
}

Deploying to a Cloud Environment

If you are deploying to a cloud environment that has multiple web server instances, you should change session state mode from "InProc" to "Custom". In addition, change the connection string named "DefaultConnection" to connect to an instance of SQL Server (including SQL Azure and SQL Compact) instead of to SQL Server Express.

Known Issues

Additional Resources

Disclaimer

This is a preliminary document and may be changed substantially prior to final commercial release of the software described herein.

The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication.

This White Paper is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT.

Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, email address, logo, person, place or event is intended or should be inferred.

© 2011 Microsoft Corporation. All rights reserved.

Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

The names of actual companies and products mentioned herein may be the trademarks of their respective owners.