When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles [1.x] [2.0]
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
Headlines from ASPWire.com
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs
















internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers
ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
Print this Page!

Windows Systems Administrator
Jupitermedia
US-CT-Darien

Justtechjobs.com Post A Job | Post A Resume

Published: Wednesday, October 11, 2006

Examining ASP.NET 2.0's Membership, Roles, and Profile - Part 6
By Scott Mitchell


A Multipart Series on ASP.NET's Membership, Roles, and Profile
This article is one in a series of articles on ASP.NET's membership, roles, and profile functionality.

  • Part 1 - learn about how the membership features make providing user accounts on your website a breeze. This article covers the basics of membership, including why it is needed, along with a look at the SqlMembershipProvider and the security Web controls.
  • Part 2 - master how to create roles and assign users to roles. This article shows how to setup roles, using role-based authorization, and displaying output on a page depending upon the visitor's roles.
  • Part 3 - see how to add the membership-related schemas to an existing database using the ASP.NET SQL Server Registration Tool (aspnet_regsql.exe).
  • Part 4 - improve the login experience by showing more informative messages for users who log on with invalid credentials; also, see how to keep a log of invalid login attempts.
  • Part 5 - learn how to customize the Login control. Adjust its appearance using properties and templates; customize the authentication logic to include a CAPTCHA.
  • Part 6 - capture additional user-specific information using the Profile system. Learn about the built-in SqlProfileProvider.
  • Part 7 - the Membership, Roles, and Profile systems are all build using the provider model, which allows for their implementations to be highly customized. Learn how to create a custom Profile provider that persists user-specific settings to XML files.
  • Part 8 - learn how to use the Microsoft Access-based providers for the Membership, Roles, and Profile systems. With these providers, you can use an Access database instead of SQL Server.
  • Part 9 - when working with Membership, you have the option of using .NET's APIs or working directly with the specified provider. This article examines the pros and cons of both approaches and examines the SqlMembershipProvider in more detail.
  • Part 10 - the Membership system includes features that automatically tally the number of users logged onto the site. This article examines and enhances these features.
  • (Subscribe to this Article Series! )

    Introduction
    The Membership API in the .NET Framework provides the concept of a user account and associates with it core properties: username, passsword, email, security question and answer, whether or not the account has been approved, whether or not the user is locked out of the system, and so on. However, depending on the application's needs, chances are your application needs to store additional, user-specific fields. For example, an online messageboard site might want to also allow users to specify a signature, their homepage URL, and their IM address.

    There are two ways to associate additional information with user accounts when using the Membership model. The first - which affords the greatest flexibility, but requires the most upfront effort - is to create a custom data store for this information. If you are using the SqlMembershipProvider, this would mean creating an additional database table that had as a primary key the UserId value from the aspnet_Users table and columns for each of the additional user properties. In the online messageboard example, the table might be called forums_UserProfile and have columns like UserId (a primary key and a foreign key back to aspnet_Users.UserId), HomepageUrl, Signature, and IMAddress.

    Rather than using custom data stores, the ASP.NET 2.0 Profile system can be used to store user-specific information. The Profile system allows the page developer to define the properties she wants to associate with each user. Once defined, the developer can programmatically read from and assign values to these properties. The Profile system accesses or writes the property values to a backing store as needed. Like Membership and Roles, the Profile system is based on the provider model, and the particular Profile provider is responsible for serializing and deserializing the property values to some data store. The .NET Framework ships with a SqlProfileProvider class by default, which uses a SQL Server database table (aspnet_Profile) as its backing store.

    In this article we will examine the Profile system - how to define the user-specific properties and interact with them programmatically from an ASP.NET page - as well as look at using the SqlProfileProvider that ships with .NET 2.0. In a future article we'll look at how to create and use a custom profile provider. Read on to learn more!

    - continued -

    An Overview of the Profile System
    The Membership system in ASP.NET 2.0 was designed to create a standardized API for working with user accounts, a task faced by many web applications (refer back to Part 1 of this article series for a more in-depth look at Membership). While the Membership system encompasses core user-related properties - username, password, email address, and so on - oftentimes additional information needs to be captured for each user. Unfortunately, this additional information can differ wildly from application to application.

    Rather than add additional user attributes to the Membership system, Microsoft instead created the Profile system to handle additional user properties. The Profile system allows the additional, user-specific properties to be defined in the Web.config file and is responsible for persisting these values to some data store. How the user-specific properties are serialized and deserialized to a backing store is the responsibility of the configured Profile provider (see A Look at ASP.NET 2.0's Provider Model for more information on the provider model and its uses). The default Profile provider - SqlProfileProvider - serializes the property values to the aspnet_Profile table in a SQL Server database.

    When working with the Profile system, keep in mind that it's sole purpose is to serve as a means for defining a set of user-specific properties and, through a particular provider, serialize those property values to some backing store.

    Defining the User-Specific Properties
    With the Profile system, the user-specific properties must be spelled out in the Web.config. For each property, you can specify the name, data type, and how the data should be serialized. There are four serialization options:

    • ProviderSpecific (the default) - the Profile provider is tasked with determining how to serialize the property value
    • String - the property value is converted to a string representation when persisted by the Profile provider;
    • Xml - the property value is converted to an XML representation when persisted by the Profile provider
    • Binary - the property value is converted to a binary representation when persisted by the Profile provider
    What serialization method you choose typically depends upon the type of the variable. You can instruct the provider to serialize the data as a String if there is a type converter for the property's data type that allows transformation to a String (such type converters exist for all of the primitive types - Strings, Booleans, Integers, and so on). To serialize as XML, the type must be XML serializable, and to serialize as Binary, the type must be marked serializable. (For more on XML serialization, see XML Serialization in ASP.NET; for info on the binary object serialization, see C# Object Serialization.)

    The user-specific properties defined in the Profile system can be simple scalar properties, scalar properties grouped into complex types, or based on pre-existing complex types (such as a class). The names, types, and serialization instructions for each Profile property is spelled out in the <profile> element's <properties> section. For example, imagine that we were creating an online messageboard and wanted to allow each user to specify a homepage URL that would appear alongside their posts. To capture this information, we could add the following profile property:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <system.web>
          ...
          
          <profile defaultProvider="CustomProfileProvider" enabled="true">
            <providers>
              ...
            </providers>
    
            <!-- Define the properties for Profile... -->
            <properties>
              <add name="HomepageUrl" type="String" serializeAs="String" />
              
              ...
            </properties>
          </profile>
        </system.web>
    </configuration>
    

    The <add> element adds a Profile property named HomepageUrl of type String and serialized as a String. There are additional attributes that can be included in the <add> element, such as defaultValue and readOnly, among others. See the technical documentation on the <add> element for more information.

    Scalar profile properties can be grouped using the <group> element. For example, in addition to the HomepageUrl property we might also want to capture biographical information for our users, including their physical location, birthdate, and programming language of choice. This information can appear as three scalar values, or can be grouped. The following markup shows how to group these three properties into a group named Bio.

    <profile defaultProvider="CustomProfileProvider" enabled="true">
      <providers>
        ...
      </providers>
    
      <!-- Define the properties for Profile... -->
      <properties>
        <add name="HomepageUrl" type="String" serializeAs="String" />
    
        <group name="Bio">
          <add name="BirthDate" type="DateTime" serializeAs="Xml" />
          <add name="Location" type="String" />
          <add name="ProgrammingLanguageOfChoice" type="ProgrammingLanguages"  />
        </group>
    
        ...
      </properties>
    </profile>
    

    In this grouping, the BirthDate property (of type DateTime) was chosen to be serialized as XML. The Location and ProgrammingLanguageOfChoice properties don't have a serializeAs attribute specified, meaning that the Profile provider being used will ascertain how to serialize these properties. Note the type for the ProgrammingLanguageOfChoice property. This is a type I created in the App_Code folder. Specifically, it's an enumeration that's defined with the following code:

    Public Enum ProgrammingLanguages As Integer
        NoneSelected = 0
        VB = 1
        CSharp = 2
        JSharp = 3
    End Enum
    

    Not only can Profile properties have enumerations as their type, but also can have custom classes as their type. In the project that can be downloaded at the end of this article you'll find a very simple Address class (also in the App_Code folder), that has properties representing an address:

    <Serializable()> _
    Public Class Address
        Public Address1 As String
        Public Address2 As String
        Public City As String
        Public State As String
        Public Zip As Integer
    End Class
    

    With this class defined, I can add Profile properties of type Address like so:

    <profile defaultProvider="CustomProfileProvider" enabled="true">
      <providers>
        ...
      </providers>
    
      <!-- Define the properties for Profile... -->
      <properties>
        <add name="HomepageUrl" type="String" serializeAs="String" />
    
        <group name="Bio">
          <add name="BirthDate" type="DateTime" serializeAs="Xml" />
          <add name="Location" type="String" />
          <add name="ProgrammingLanguageOfChoice" type="ProgrammingLanguages"  />
        </group>
    
        <add name="BillingAddress" type="Address" serializeAs="Xml" />
        <add name="ShippingAddress" type="Address" serializeAs="String" />
      </properties>
    </profile>
    

    Both the BillingAddress and ShippingAddress properties are of type Address. BillingAddress is serialized as XML, while ShippingAddress is serialized using Binary serialization. (In order to support binary serialization, the property's type must implement ISerializable or have the Serializable attribute applied.)

    Working with the Profile Properties in Code
    After defining your Profile properties, the ASP.NET engine automatically creates a ProfileCommon class that has properties that map to the properties defined in Web.config (which allows for IntelliSense and compile-time type checking). This class is dynamically recreated whenever the properties defined in Web.config are modified and automatically works with the currently logged on user's profile. (You can also turn on profile support for anonymous users, and later migrate their profile data once they've logged on. But this topic is beyond the scope of this article, and will have to wait for a future installment of this series!)

    The custom ProfileCommon class is accessible in the code portion of an ASP.NET page through the HttpContext object's Profile property. For example, to read the currently logged on user's HomepageUrl property from an ASP.NET page, simply use Profile.HomepageUrl. In fact, as soon as you type in Profile and hit period, IntelliSense brings up the various properties. Cool, eh? And the grouping functionality works as you'd expect. Type in Profile and hit period, and one of the properties is Bio. Enter Bio and hit period, and the three scalar properties appear in IntelliSense (BirthDate, Location, and ProgrammingLanguageOfChoice).

    The Profile property offers IntelliSense and compile-time type checking!

    The download available at the end of this article has three Web pages worth examining. The first is /UsersOnly/Default.aspx and shows the currently logged on user's Profile information. The second page, /UsersOnly/UpdateProfile.aspx, allows the currently logged on user to update his Profile data. The third page demonstrates the Profile property's GetProfile("username") method, which can be used to get the Profile data for a user other than the currently logged-on user. The page /UserList.aspx lists all of the users in the system, including their membership information (their username, email, and so on) and HomepageUrl Profile property value.

    Specifying a Profile Provider
    If you don't explicitly specify a Profile provider, the default provider - SqlProfileProvider - is used. This default provider stores each user's property values in the aspnet_Profile table. The aspnet_Profile stores each users profile settings in a single row in the table, using a rather inefficient means for storing the property names, data types, and values. The table's schema follows:

    aspnet_Profile
    UserIduniqueidentifier; PK; FK to aspnet_Users
    PropertyNamesntext
    PropertyValuesStringntext
    PropertyValuesBinaryimage
    LastUpdatedDatedatetime

    For a given record, the PropertyNames column contains each of the Profile property names along with how they are serialized and where in the PropertyValuesString or PropertyValuesBinary columns their values can be found. The values for each property are squished into the PropertyValuesString or PropertyValuesBinary columns, with String- and XML-serialized properties tucked in PropertyValuesString and Binary-serialized properties jammed in PropertyValuesBinary.

    With our Profile properties, the PropertyNames column for a user will have a value like:

    Bio.ProgrammingLanguageOfChoice:S:0:92:HomepageUrl:S:92:30:ShippingAddress:B:0:212:...

    As you can see, each property name has the format PropertyName:B|S:StartIndex:Length, with the B or S indicating whether the property's value can be found in PropertyValuesString (S) or PropertyValuesBinary (B). For example, the Bio.ProgrammingLanguageOfChoice property value is stored in PropertyValuesString (S) starting at position 0 with a length of 92. The HomepageUrl property is also serialized as a String and its value can be found at index 92 with a length of 30.

    Looking at the PropertyValuesString column (where the String- and XML-serialized property values are stored), we find:

    <?xml version="1.0" encoding="utf-16"?><ProgrammingLanguages>CSharp</ProgrammingLanguages>http://www.datawebcontrols.com...

    The value for the ProgrammingLanguageOfChoice has been serialized as XML, starts at index 0, and is 92 characters long. Likewise, the HomepageUrl property starts at index 92 and has a length of 30 characters. (The ShippingAddress property uses Binary-serialization, and therefore is found in the PropertyValuesBinary table. As you can see from inspecting the PropertyNames column, the ShippingAddress value begins at index 0 and has a length of 212 bytes.)

    All of the work of serializing Profile properties to the database is handled automatically by the SqlProfileProvider. The table and stored procedures used by the SqlProfileProvider are automatically created when implementing the SqlMembershipProvider (see Part 1).

    Performance and Querying Limitations of the SqlProfileProvider
    Since the SqlProfileProvider squishes all of the Profile property values into one or two columns in a single row, each time any Profile property is read or written to, all of the Profile values must be serialized or deserialized. Additionally, the format of the data makes it next to impossible to query or report on the Profile information. Imagine that we wanted to determine how many users in our system used C#. Since that information is jammed into the PropertyValuesString column, determining this information would require expensive string processing or some routine that first "unpacks" the data into a normalized structure.

    An alternative to the built-in SqlProfileProvider is the free Table Profile Provider created by Microsoft employee Hao Kung. This provider stores each Profile property as a separate database table column. Alternatively, you could create your own custom Profile provider that operates against existing database tables or uses some other data store (such as XML files, text files, Web services, and so on).

    Conclusion
    ASP.NET 2.0's Membership system makes creating and managing user accounts a piece of cake. Unfortunately, the Membership system only defined the most basic of user-specific properties - username, password, email address, and so on. If you need to capture additional information about your users, you must either use a custom solution (create your own data store, write code to read and write data to this store, and so on) or use the Profile system. The Profile system allows page developers to define a set of user-specific properties in Web.config. This information is automatically translated into a class (ProfileCommon), which is accessible through the HttpContext class's Profile property.

    ASP.NET 2.0 ships with a default Profile provider, SqlProfileProvider, which stores the Profile property values in the aspnet_Profile table in a SQL Server database. This provide automatically handles all of the serialization and deserialization work, you just need to programmatically read from and write to the user's Profile data through the Profile property.

    Happy Programming!

  • By Scott Mitchell


    Attachments

  • Download the code used in this article

    A Multipart Series on ASP.NET's Membership, Roles, and Profile
    This article is one in a series of articles on ASP.NET's membership, roles, and profile functionality.

  • Part 1 - learn about how the membership features make providing user accounts on your website a breeze. This article covers the basics of membership, including why it is needed, along with a look at the SqlMembershipProvider and the security Web controls.
  • Part 2 - master how to create roles and assign users to roles. This article shows how to setup roles, using role-based authorization, and displaying output on a page depending upon the visitor's roles.
  • Part 3 - see how to add the membership-related schemas to an existing database using the ASP.NET SQL Server Registration Tool (aspnet_regsql.exe).
  • Part 4 - improve the login experience by showing more informative messages for users who log on with invalid credentials; also, see how to keep a log of invalid login attempts.
  • Part 5 - learn how to customize the Login control. Adjust its appearance using properties and templates; customize the authentication logic to include a CAPTCHA.
  • Part 6 - capture additional user-specific information using the Profile system. Learn about the built-in SqlProfileProvider.
  • Part 7 - the Membership, Roles, and Profile systems are all build using the provider model, which allows for their implementations to be highly customized. Learn how to create a custom Profile provider that persists user-specific settings to XML files.
  • Part 8 - learn how to use the Microsoft Access-based providers for the Membership, Roles, and Profile systems. With these providers, you can use an Access database instead of SQL Server.
  • Part 9 - when working with Membership, you have the option of using .NET's APIs or working directly with the specified provider. This article examines the pros and cons of both approaches and examines the SqlMembershipProvider in more detail.
  • Part 10 - the Membership system includes features that automatically tally the number of users logged onto the site. This article examines and enhances these features.
  • (Subscribe to this Article Series! )


    Windows Internet Technology | ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article



  • JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

    Solutions
    Whitepapers and eBooks
    Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
    Microsoft Article: 7.0, Microsoft's Lucky Version?
    Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Windows Server 2008
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES