uppose you are developing a new web site and want to implement forms authentication. The web site will have a user registration page, a login page, and one or more pages that you must secure. The user registration and login pages use ASP.NET AJAX for an enhanced user experience. Also, the site must capture details such as birth date and address at the time of registration. This information is to be stored in the Profile of the user.
Figure 1. Creating a New ASP.NET AJAX-enabled Web Site
Configuring the Web Site
Before you begin coding, configure the web site for forms authentication as well as Membership and Profile services. Open a web.config file in your Visual Studio IDE and add the following markup inside the connectionStrings section:
You specified a database connection string named connstr that points to a Northwind database. Make sure to change the connection string to match your development environment. I assume that your database is configured for application services using the aspnet_regsql.exe tool. You will use this connection string while configuring membership and profile providers.
Now, add the following markup inside the system.web section:
Review the above markup carefully, and you'll notice the following:
- The authentication section sets the authentication mode to Forms. The forms tag sets the URL of the login page by using the loginUrl attribute.
- The authorization section disables anonymous users by setting the users attribute of the deny tag to "?".
- The membership section configures a membership provider named p1. (You can change this any name you choose.)
- The connectionStringName attribute specifies the database that will be used for storing membership information.
- The type attribute indicates the class that will act as the membership provider. You use the built-in SQL Membership provider called SqlMembershipProvider.
- The requiresQuestionAndAnswer attribute indicates that you do not intend to accept a secret question and answer from the end user at the time of registration.
- The profile section configures a profile provider named p2 and various profile properties. The significance of the connectionStringname and type attributes is same as for the membership section. Note, however, that this time the type is a SqlProfileProvider class. The properties section defines profile properties and groups.
- You defined two simple properties called FullName and DOB and a property group called Address. The Address group further contains three properties: street, country, and postalcode. The DOB property is of type DateTime; therefore, its type attribute is set to System.DateTime.
Now that you have configured your web site for using forms authentication and membership services, it's time to expose Membership and Profile services to the client-side AJAX code. The web.config file will have a pre-defined section called webServices. By default, all its content is commented. You need to un-comment and modify it so that it looks as shown below:
The authenticationService tag is used to expose forms authentication and membership services to AJAX code. The enabled attribute governs whether AJAX code can avail membership services. The requireSSL attribute indicates whether the authentication is happening over SSL. Similarly, the Profile service is exposed to AJAX code by using the profileService tag. The readAccessProperties and writeAccessProperties attributes of the profileService tag specify the profile properties that are readable and writable, respectively. Notice how the grouped properties are specified using the dot (.) notion. If you do not include a specific profile property in these attributes, it will not be accessible to the client code.
Applying forms authentication ensures that all the forms of the web site except the login page are secured. However, you want your registration page to be unsecured because new users will need to access it. Do this by adding a location section in the web.config file as shown below:
The path attribute of the location tag specifies a virtual path of a file or folder that is to be configured. It then allows access to all the users using the authorization section and allow tag.
This completes the web site configuration. Now, you will move on to develop the required web forms.
First of all, you will create the user registration page. Add a new web form named Registration.aspx. Drag and drop a ScriptManager control from the toolbox (see Figure 2).
Also, drag and drop an UpdatePanel and UpdateProgress control on the web form. The UpdatePanel control represents a part of the total web form that can be refreshed without causing a post back of the entire form. The UpdateProgress control is used to display a progress message while the UpdatePanel is being refreshed.
Drag and drop a Label control inside the UpdateProgress control and set its Text property to "Please wait...". Also, set its AssociatedUpdatePanelID property to the ID of the UpdatePanel control. The AssociatedUpdatePanelID property links the UpdateProgress with an UpdatePanel.
The first column of the table contains Label controls that act as prompts for the textboxes. The second column of the table contains TextBox controls. Each TextBox control is validated by using a RequiredFieldValidator control. The TextMode property of the password and confirm password textboxes is set to Password. Similarly, the TextMode property of the street address textbox is set to MultiLine.
You might be wondering why you added a web method inside a web form. Remember that you have a "Check Availability" button that is supposed to check whether the specified user ID is available for registration. You will be making an AJAX call to do that. ASP.NET AJAX allows you to call web methods defined in web forms via an object called PageMethods. Therefore, you marked the CheckAvailability() method with a [WebMethod] attribute. Note that you must refer to the System.Web.dll and import the System.Web.Services namespace to use the [WebMethod] attribute.
The CheckAvailability() method accepts a user ID and returns true if that ID is available for registration. Inside, it calls the GetUser() method of the Membership object. The GetUser() method returns an instance of the MembershipUser class that represents the specified user. If it returns null, it indicates that the specified user doesn't exist and accordingly true or false is returned to the caller.
When the user clicks the Register button, you need to add user details in the membership and profile tables. Use the Membership and Profile objects to do this BECAUSE ASP.NET AJAX doesn't allow you to create users from client-side code. The following code shows the Click event handler of the Register button:
protected void Button1_Click(object sender, EventArgs e)
MembershipUser user = Membership.CreateUser
(TextBox2.Text, TextBox3.Text, TextBox5.Text);
ProfileCommon pc = Profile.GetProfile(user.UserName);
pc.FullName = TextBox1.Text;
pc.DOB = DateTime.Parse(TextBox6.Text);
pc.Address.Street = TextBox7.Text;
pc.Address.Country = TextBox8.Text;
pc.Address.PostalCode = TextBox9.Text;
lblMsg.Text = "User created successfully!";
catch (Exception ex)
lblMsg.Text = ex.Message;
You call the CreateUser() method of the Membership object to create the user and pass user ID, password, and email. The CreateUser() method returns an instance of MembershipUser representing the newly created user. At this point, the user is not authenticated, so you cannot set the user's profile directly via the Profile object. Instead, you call the GetProfile() method of the Profile object. The GetProfile() method returns an instance of the ProfileCommon class. Through this instance, you set various profile properties. Once all the profile properties are saved, the Save() method of the ProfileCommon class is called to save profile information to the underlying database. A success message is then displayed in a Label control. Any exceptions during the registration process are captured BY using try-catch blocks and an error message is displayed in a Label control.
Now, code the client-side CheckAvailability() function. Switch to the HTML source view of the Register.aspx and add a script block in the HEAD section of the page. Then, add the following functions in the script block:
alert('Please enter user ID!');
lblMsg.innerText="The ID is available!";
lblMsg.innerText="The ID is unavailable!";
This completes your registration page. To test it, run the Register.aspx in the browser and try creating new users. Also, check how the "Check Availability" button works. Figure 4 shows a sample run of the web form.
Figure 4. Sample Run of the Web Form
Developing a Login Page
Now that users can register themselves with the web site, you need to provide a facility that enables them to log in and access various pages. To do so, add a new web form called Login.aspx to the web site. Remember that you have set the loginUrl attribute of the forms tag to Login.aspx. Drag and drop a ScriptManager control on it and design the login page as shown in Figure 5 by assembling various controls.
Figure 5. The Login Page Design
A user ID
A boolean value indicating whether an authentication cookie will be persistent
The web page where the user should be redirect after a successful login
Reserved for future use
A callback function that will be called after a successful login (EndAuthenticateUser in this example)
A callback function that will be called in case a login attempt fails (OnError in this example)
A custom value that is passed to the callback functions
If the user is successfully authenticated, the EndAuthenticateUser function will be called. The following is the EndAuthenticateUser function:
alert("Unable to login! Please check user id and password!!");
The EndAuthenticateUser() function takes three parameters: the result of the login operation, the user context that you passed earlier in the eighth parameter of the login() method, and the method name. Inside, it checks whether the result is true (in other words, the user is successfully authenticated) and, if so, it sets the location property of the windows object to default.aspx. This way, the user is redirected to the default page after a successful login attempt. If there is any error, an error message is displayed using the alert() function.
The OnError() function is called whenever an error occurs when calling the authentication service. This function is shown below:
The function simply displays an error message to the user. The result parameter received is actually an object and has a method called get_message() that returns a descriptive error message.
This completes the login page.
Implementing Logout Functionality
Add another web form called Default.aspx. This web form will allow users to logout and manage their profiles. Firstly, you will implement logout functionality. Drag and drop a ScriptManager control on the Default.aspx and design the web form as shown in Figure 6.
protected void Page_Load(object sender, EventArgs e)
Label4.Text = Membership.GetUser().UserName;
The code simply retrieves the user name of the current user and assigns it to the label. Note that the GetUser() method of the Membership object returns an object of type MembershipUser. The UserName property of the MembershipUser class is then called. You need to display the user name from the server-side code because ASP.NET AJAX doesn't provide any way to retrieve it via client-side code.
- The first parameter indicates a URL where the user should be taken after successful logout.
- The second parameter specifies a callback function to be called when the logout operation is complete.
- The third parameter specifies a callback function to be called when the logout operation fails.
- The fourth parameter indicates a custom context information.
if(event.srcElement.value=="Show my profile")
event.srcElement.value="Hide my profile";
event.srcElement.value="Show my profile";
The BeginProfileLoad() function toggles visibility of the profile panel. If the profile panel is to be displayed, then you must populate various textboxes with profile values. The ASP.NET AJAX framework provides a class called ProfileService that allows you to work with profile properties. The load() method of the ProfileService class loads profile property values. The load() method takes four parameters, which do the following:
An array of property names that are to be loaded. If you have too many profile properties, then it makes sense to load the ones that you really want to use. This will improve the performance of your page.
A callback function that will be called when the load operation is completed
A callback function that will be called if the load operation fails
Custom context information, if any
function EndProfileLoad(numProperties, userContext, methodName)
The EndProfileLoad() function receives three parameters: number of properties that are loaded, context information that is supplied to the load() function, and method name. It then populates the textboxes with the profile property values. The ProfileService class exposes profile properties via the properties collection. Remember that only the properties specified in the readAccessProperties attribute of the profileService tag of web.config are exposed. The properties and groups are accessed with the familiar dot (.) notion.
When profile property values are displayed in various textboxes, the user can change them and click on the "Save Profile" button. Clicking on the "Save Profile" button calls the BeginSaveProfile() function, which is shown here:
The code again uses the ProfileService class and its properties collection to assign new values. Once all the profile properties are set, it calls the save() method of the ProfileService class. The save() method takes the same four parameters as the load() method (in other words, the array of properties to write, the callback function to be called after successful saving, the callback function to be called after unsuccessful save, and custom context information). The EndSaveProfile() function simply displays a message box to the user:
function EndSaveProfile(numProperties, userContext, methodName)
alert('Your profile is saved successfully!');
ASP.NET AJAX provides a handy way to consume membership and profile features. To consume these features, you need to enable them by using the authenticationService and profileService tags of web.config. Once enabled, you can use the AuthenticationService and ProfileService classes to consume them.