Using the SQL Table Profile Provider in ASP.NET 4 Web Applications (C# & VB)

This post and accompanying projects demonstrate how to use Microsoft's SQL Table Profile Provider with an ASP.NET Web application.

ASP.NET's built-in Profile provider (SqlProfileProvider) stores Profile data in an oddball, serialized format that’s hard to use in queries and may not scale well in large sites.

To help developers use a more standard database format, Microsoft posted the source code for a sample provider (SqlTableProfileProvider). It stores each Profile property in a separate database column.

The SqlTableProfileProvider includes instructions and sample code for its use in file-based ASP.NET web sites where much of the Profile code is generated dynamically by ASP.NET. However, there's no documentation or sample showing  how to use SqlTableProfileProvider in a pre-compiled Web application.

A group of Microsoft MVPs took on the issue. This project and article are the results.

Of course, it would be better if  Microsoft provided a solution that's an integral and supported part of ASP.NET. If you agree, please vote for the enhancement on Microsoft Connect.

Source Code

If you’d rather stop reading and just get straight to the projects, they’re on the MSDN Code Gallery in the sample’s Downloads tab. Click here for the C# code and here for the VB code.

Resources Required

Installation of this Sample

For the easiest installation (without the need to fix file paths), unzip this solution into a folder named c:\aspnet4profile to create a folder structure like this:

 
c:\aspnet4profile
   aspnet4profile.sln
   \aspnet4profilecs
   \SQLTableProfileProviderCS

Open the solution in Visual Studio 2010, build, and browse to default.aspx.

Technical Discussion

The sample solution includes two projects: a Web application named aspnet4profilecs and the SQLTableProfileProvidercs class library. The Web application references the SQLTableProfileProviderCS.dll.

SqlTableProfileProvider.cs

The file SqlTableProfileProvider.cs is the provider source code as released by Microsoft. Read the author's White Paper for implementation details.

SqlStoredProcedureProfileProvider.cs

SqlStoredProcedureProfileProvider.cs is an alternate implementation provided by Microsoft that uses stored procedures for database access. This code is not used in this project, except for a couple of routines that detect the connection configuration. For details, see the author's White Paper.

ProfileCommon.cs

ProfileCommon.cs is where you manually insert the profile properties that you are storing in the database table.

Recall that in a file-based Web site, the run-time compiler reads the Profile properties from the web.config file and generates the required code dynamically. Profile properties look like this:

<profile enabled="true" >
    <properties>
        <add name="FirstName" />
    </properties>          
</profile>

Important: The preceding web.config markup must not be part of a Web application using the SqlTableProfileProvider described here. Instead, you  create equivalent properties in code inside ProfileCommon.cs as shown in the excerpt below:

[CustomProviderData("FirstName;nvarchar")]
public virtual string FirstName
{
    get
    {
        return ((string)(this.GetPropertyValue("FirstName")));
    }
    set
    {
        this.SetPropertyValue("FirstName", value);
    }
}

The trick in getting the class to work is the decoration [CustomProviderData("FirstName;nvarchar")] where you tell ASP.NET the name of the Profile property (FirstName) and the SQL Server data type (e.g., nvarchar) to expect.

BTW, if you're using Profiles for anonymous users, there's an additional decoration,

[SettingsAllowAnonymous(true)]
[CustomProviderData("FirstName;nvarchar")]

Telling ASP.NET to Use SQLTableProfileProvider

The <profile> node in our project's web.config file tells ASP.NET to use the custom SQLTableProfileProvider rather than the built-in default version. In the snippet below you can see the inherits attribute's value tells ASP.NET the type followed by a comma and then the assembly where it can find the type.  The table attribute points to the name of the SQL database table where the Profile data is being stored. In this case the table name is aspnet_Profile2.

<profile enabled="true" 
        defaultProvider="TableProfileProvider"  
        inherits="Microsoft.Samples.ProfileCommon,SQLTableProfileProviderCS">
  <providers>
    <clear/>
    <add name="TableProfileProvider"
            type="Microsoft.Samples.SqlTableProfileProvider, SQLTableProfileProviderCS"
            connectionStringName="LocalSqlServer" table="aspnet_Profile2" 
            applicationName="/" />
  </providers>
</profile>

Creating the New Database Table

Because you're no longer using the default Profile Provider, you won't be using the default database table. Instead, you must add a new table to the database (ASPNETDB.MDF in our case) to support separate profile fields. You'll find a small starter sample SQL script in the Web project's App_Data folder. As you can see from the following excerpt the script creates the Profile data columns (such as FirstName, LastName, Age) along with other columns required by the base provider:

CREATE TABLE [dbo].[aspnet_Profile2](
    [UserID] [uniqueidentifier] NOT NULL,
    [FirstName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [Age] [int] NULL,
    [DateOfBirth] [datetime] NULL,
    [ProfileVersion] [int] NULL,
    [LastUpdatedDate] [datetime] NOT NULL,
CONSTRAINT [PK_Profile_UserProfile2] PRIMARY KEY CLUSTERED

The easiest way to run a SQL script is to open the database in SQL Server Management Studio Express.

Using ProfileCommon in ASP.NET Pages

You use the ProfileCommon class much like you use ASP.NET's auto-generated version. The page  registeredonly.aspx is accessible only by logged in users. You call GetUserProfile() to get the Profile data for the current authenticated user.

ProfileCommon Profile = ProfileCommon.GetUserProfile();

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        txtFirstName.Text = Profile.FirstName;
        txtLastName.Text = Profile.LastName;
        txtAge.Text = Convert.ToString(Profile.Age); 
    }
}

Support

Please post your questions about the custom SQLTableProfileProvider in the ASP.NET Forums rather than contacting us directly. Thanks.

Help Us Help You

If you agree that using the SQLTableProfileProvider in ASP.NET Web applications is harder than it needs to be, please vote for the product feedback called Add Support for the SQL Table Profile Provider in ASP.NET 4 Web Applications on Microsoft Connect.

Credits

Code sample: Imar Spaanjaars (MVP)
VB conversion and documentation: Ken Cox (MVP)
Debugging: Jason Gaylord (MVP)
Alternate solution: Eugene Agafonov (MVP)
Moral support: Peter Kellner (MVP) and Charles Nurse (MVP)

Ken

10 Comments

  • thanks for the information, currently I'm looking for information about using the SQL table profile provider in ASP.NET 4

  • Glad to help (in the moral support category)

  • @Peter: Good job at raising awareness!

    @Everyone: Don't forget to vote up the feature request here:

    https://connect.microsoft.com/VisualStudio/feedback/details/595053/add-support-for-the-sql-table-profile-provider-in-asp-net-4-web-applications


    Ken

  • Will this work for MySql?

  • How would I go about using this to update Profiles other than the current authenticated user?

  • This is nice post. Its really helpful for me and this link
    http://mindstick.com/Blog/225/Profile%20in%20ASP%20net

    also helped me to complete my task.

    Thanks!!

  • Hi Ken, great code. thank you. I included on my website with success for authenticated users, on the other hand I dont know how I can include anonymousidentification to profiles using the proposed scheme. I´m trying to use AnonymousIdentification_Creating in global.asax but with limited success. Do you have the chance to shed light on the best approach to use anonymousidentification=true with sql table profile provider?. Brgds!

  • The SQL standard names are LOWER and UPPER, not LCASE and UCASE. Some pruodcts like MySQL alias LCASE and UCASE to the LOWER and UPPER functions for increased compatibility with other non-standard pruodcts and some pruodcts that are not databases. MS Access uses LCASE and UCASE as does the non-database pruodcts Excel and OOCalc. There are some programming languages which use LCASE and UCASE. There may be other DB pruodcts that do not use the SQL standard LOWER/UPPER names for these functions. Oracle does use LOWER/UPPER. DB2 supports both. PostgreSQL uses LOWER/UPPER.

  • We use the original SQLTableProfileProvider extensively in our web sites - but the thought of having dozens of these separate assembly projects out there is not only painful because it adds another project for every single web site we have, but dangerous when the developers start accidentally start replacing the wrong copy in a web site because they didn't think to give it a new name.
    Isn't there a way to do the same thing using a local file (partial class, etc) or something

  • I am using your code and noted in the profilecommon.vb an entry to create a username object in the profile directly from the membership system (without associated table field in the SQL Profile2 table).

    My question is could this be extended to created the IsApproved, IsLockedOut objects too?

    I have tried referencing the getuser.isappproved but it doesn't work.

    I hope you can help?

Comments have been disabled for this content.