RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Writing A Custom Membership Provider for your ASP.NET 2.0 Web Site : Page 3

If you have an ASP.NET Web site that stores any registration or log in information for your users, you probably know that the Membership provider in ASP.NET 2.0 uses a SQL Server Express 2005 database. But what if you want to use something else? This article will show you to use your own data source for storing membership information.

Implementing Your Own Custom Provider
Before you learn how to implement your own custom provider, you need to understand the provider object model in ASP.NET 2.0. The default membership provider in Beta 2 is known as SqlMembershipProvider and it contains methods and properties specific to using SQL Express 2005 as a data store for membership information. It inherits from the MembershipProvider class, which provides data store-agnostic methods for storing membership information. The MembershipProvider class itself inherits from the ProviderBase class, the root of all providers (see Figure 6).

Figure 6. Providers: The provider model class hierarchy is shown.
If you just want to modify some of the implementations of the existing SQL membership provider (such as changing the way passwords are hashed or encrypted), then you simply need to create a class that inherits from SqlMembershipProvider and override the methods of concern, like this:

Public Class ModifiedSqlMembershipProvider
   Inherits SqlMembershipProvider

   Public Overrides Function CreateUser (...)
   End Function
End Class
However, if you do not want to use the SqlMembershipProvider supplied in Beta 2 (for example if you are creating your own custom data store for saving members' information, like using an Access database), then you need to implement your own class and inherit from the MembershipProvider class. The MembershipProvider class contains methods and properties for manipulating membership information, and when inheriting from this class you need to provide the implementation for all its methods and properties.

For simplicity, I will only provide the implementation for allowing users to register for a new account and to login to a Web site. For all of it, I will use the CreateUserWizard and Login controls.

Right-click on the project name in Solution Explorer and select Add New Item…. Select the Class template and name it as AccessMembershipProvider.vb. Click OK. You will be prompted to save the file in the App_Code folder. Click Yes.

First, import the System.Data namespace for database access:

Imports System.Data
Next, inherit from the MemberShipProvider class:

Public Class AccessMembershipProvider
   Inherits MembershipProvider

End Class
You will notice that Visual Studio 2005 will automatically add all the stubs for the methods that you need to override in the base class.

As the SqlMembershipProvider is the default provider used by the various security controls, you need to register the new membership provider you are creating in this article so that the ASP.NET runtime will now use your custom provider. To do so, add a Web.config file to your project (right-click on project name in Solution Explorer and select Add New Item…. Select the Web Configuration File template and click OK.

   <authentication mode="Forms"/>
      defaultProvider="AccessMembershipProvider" >
         <add name="AccessMembershipProvider" 
          OLEDB.4.0;Data Source=C:\NewMembershipProvider\
          App_Data\Members.mdb;Persist Security 
          Info=False" />
Note the following:
  • Authentication mode should be "Forms."
  • Add the new provider "AccessMembershipProvider" using the <add> element.
  • Specify the requiresQuestionAndAnswer attribute to "true" (you will see how this is used in later in this article).
  • Specify the connection string to the Access database in the connectionString attribute.
  • Specify the default membership provider as "AccessMembershipProvider" using the defaultProvider attribute in the <membership> element.
In general, you can specify any attribute name you like in the <add> element. The values of these attributes will be retrieved by the implementation of the provider (AccessMembershipProvider.vb, in this case).

In AccessMembershipProvider.vb, add the following private member variables:

    '---for database access use---
    Private connStr As String
    Private comm As New OleDb.OleDbCommand

    Private _requiresQuestionAndAnswer As Boolean
    Private _minRequiredPasswordLength As Integer
Add the following Initialize() method:

Public Overrides Sub Initialize( _
   ByVal name As String, _
   ByVal config As _

    '===retrives the attribute values set in 
    'web.config and assign to local variables===

   If config("requiresQuestionAndAnswer") = "true" Then _
       _requiresQuestionAndAnswer = True

   connStr = config("connectionString")
   MyBase.Initialize(name, config)
End Sub
The Initialize() method will be fired when the provider is loaded at runtime. The values specified in the attributes of the <add> element in Web.config will be passed into this method through the config parameter. To retrieve these attributes values, specify the config parameter using the name of the attribute, like this:

   If config("requiresQuestionAndAnswer") = "true" Then _
       _requiresQuestionAndAnswer = True

   connStr = config("connectionString")
In this case, I have retrieved the requiresQuestionAndAnswer and connectionString attribute values and saved them to the private variables declared earlier.

The requiresQuestionAndAnswer attribute value is used to set the RequiresQuestionAndAnswer property:

Public Overrides ReadOnly Property _
   RequiresQuestionAndAnswer() _
   As Boolean
        If _requiresQuestionAndAnswer = True Then
            Return True
            Return False
        End If
    End Get
End Property
It is important to set this property; if you don't, the password question and password answer textboxes will not be shown in the CreateUserWizard control (see Figure 7).

Figure 7. Question and Answer: If you don't set the RequiresQuestionandAnswer property the CreateUserWizard control will display without the password question and answer textboxes.
The CreateUserWizard control will invoke the CreateUser() method when the user clicks on the Create User button, so the next step you need to perform is to code this method (see Listing 1).

In this method, you can perform all the checks to ensure that the user has entered all the necessary information, such as the minimum number of characters for the password, to ensure that the password question and answer are supplied, etc. Once all these data are available, you can proceed to add the user information to your own custom data store—an Access database, in this case.

If the creation of the user is successful, you need to return a MembershipUser object. You also need to return the status of the creation through the status parameter (passed in by reference (ByRef)).

To ensure that the Login control validates user login through your custom database, you also need to implement the ValidateUser() method:

Public Overrides Function ValidateUser( _
   ByVal username As String, _
   ByVal password As String) As Boolean

    Dim conn As New OleDb.OleDbConnection(connStr)
        Dim sql As String = _
           "Select * From Membership WHERE " & _
           "username=@username AND password=@password"
        Dim comm As New OleDb.OleDbCommand(sql, conn)
        comm.Parameters.AddWithValue("@username", _
        comm.Parameters.AddWithValue("@password", _
        Dim reader As OleDb.OleDbDataReader = _
        If reader.HasRows Then
            Return True
            Return False
        End If

    Catch ex As Exception
        Return False
    End Try
End Function
Figure 8. Registering: This is the UI for creating a new user account.
The ValidateUser() method is fired when the user clicks on the Log In button in the Login control. Here I basically retrieve any record that matches the supplied username and password. If there is at least one record, then the login is successful and the function returns a "true" value.

Testing the Application
That's it! Press F5 to test and debug the application. Figure 8 shows what happens when you try to register for a new user account.

Once the account is created, click on the Login hyperlink to test the new account. If you are successfully authenticated, you should see the login name (in my case it is "weimeng") used to login to the site (see Figure 9).

Figure 9. Logging In: This is the UI for logging in to the site using an existing username/password combination.

To verify that you are actually using the new membership provider, open the Access database and check that the user account is present in the table.

In this article, you have seen that creating your own custom provider is not a very difficult task. Creating a custom provider allows you to choose the best solution for your application, without being restricted to what is available. And this is precisely the design goal of the ASP.NET team—make Web development easy and at the same time extensible.

Wei-Meng Lee is a Microsoft MVP and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. He is an established developer and trainer specializing in .NET and wireless technologies. Wei-Meng speaks regularly at international conferences and has authored and coauthored numerous books on .NET, XML, and wireless technologies. He writes extensively on topics ranging from .NET to Mac OS X. He is also the author of the .NET Compact Framework Pocket Guide, ASP.NET 2.0: A Developer's Notebook (both from O'Reilly Media, Inc.), and Programming Sudoku (Apress). Here is Wei-Meng's blog.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date