Customizing Login Controls

Starting from ASP.NET 2.0, ASP.NET provides a set of controls related to login, change password, creation of user etc. These controls are called as login controls. Internally they make use of Membership API, which is a set of classes to perform the required operations. In turn, Membership API calls stored procedures and accesses tables in a database.

When you use Login controls, they make use of a database automatically created at the time of configurating website using ASP.NET Configuration tool. This database is named as ASPNETDB.MDF and placed in APP_DATA folder of the website.

In this blog, I build a small application that shows how to use login controls - Login, LoginName, LoginStatus and CreateUserWizard. The theme of this blog is to explain how you can customize these controls look and functionality.

The sample project does the following things.

Steps To Create and Confiure the project

Let us go through the steps required to create this application. The code used in this project is also shown as it is. You can copy the code and paste it into your pages.
  1. Create a new empty web application using File->New WebSite  of Visual Web Developer. You can as well use Visual Studio.NET. I prefer to use Visual Web Developer 2008 for it speed.
  2. Use Project-> ASP.NET Configuration to confiure website to use memebership.
  3. Select Security Tab and use Security Setup Wizard.  Select option From Internet  in second step.
  4. In step 6, specify you want to deny access to anonymous users.
  5. At the end of configuration (after you come back to project) web.config and ASPNETDB.MDF are created.
  6. Add USERS_PROFILE table to ASPNETDB.MDF
    username   nvarchar(256)  - Primary key
    fullname   nvarchar(256)
    occupation nvarchar(256)
    
  7. Create a folder called all and make it accessible to all by placing a web.config file with configuration sections as follows.
    <configuration>
        <appSettings/>
        <connectionStrings/>
        <system.web>
          <authorization>
            <allow users="*"/>
          </authorization>
        </system.web>
    </configuration>
    
  8. Place register.aspx in all folder
  9. Place login.aspx and default.aspx in root folder
  10. Create a folder called photos in root folder. This folder contains photos of users
  11. Open login.aspx and place Login control in it.
  12. Select smart tag of Login control and select option Convert To Template. This converts login control to a template. Modify the template to suite your requirement. You can add or delete components.  I have made some changes. The following code shows login.aspx after Login control is customized.
    <%@ Page Language="C#" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <script runat="server">
    </script>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Login</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <center>
            <asp:Login ID="Login1" runat="server">
                <LayoutTemplate>
                    <h3>Login</h3>
                    <table border="0" cellpadding="5pt">
                        <tr>
                            <td align="right">
                                <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">Enter User 
                                         Name:</asp:Label>
                            </td>
                            <td>
                                <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                                <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName"
                                    ErrorMessage="User Name is required." ToolTip="User Name is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator>
                            </td>
                        </tr>
                        <tr>
                            <td align="right">
                                <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password">Enter Password:</asp:Label>
                            </td>
                            <td>
                                <asp:TextBox ID="Password" runat="server" TextMode="Password"></asp:TextBox>
                                <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"
                                    ErrorMessage="Password is required." ToolTip="Password is required." ValidationGroup="Login1">*</asp:RequiredFieldValidator>
                            </td>
                        </tr>
                    </table>
                    <p />
                    <asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="Log In" ValidationGroup="Login1" />
                    <p />
                    <asp:Literal ID="FailureText" runat="server" EnableViewState="False"></asp:Literal>
                    <p />
                    <a href="all/register.aspx">New User? Register Here!</a>
                </LayoutTemplate>
            </asp:Login>
        </center>
        </form>
    </body>
    </html>
            
    
  13. Place CreateUserWizard control in register.aspx. Select its smart tag and select Customize Create User Step. It expands CreateUserWizardStep with ContentTemplate. Place some more control in its content template as shown in register.aspx.
  14. Go to CreateUserWizard control's properties and click on events icon. Double click on CreatedUser event to write code for that event. The code takes data entered in fullname and occupation textboxes. It inserts this data into USERS_PROFILE table. Finally it uploads the photo selected by the users into photos folder with the name <usernam>.jpg
    <%@ Page Language="C#" %>
    
    <%@ Import Namespace="System.Data.SqlClient" %>
    <%@ Import Namespace="System.Data" %>
    <%@ Import Namespace="System.Web.Configuration" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script runat="server">
        protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
        {
            string username = CreateUserWizard1.UserName;
            // take fullname
            TextBox tb = (TextBox)CreateUserWizardStep1.ContentTemplateContainer.FindControl("txtFullname");
            string fullname = tb.Text;
    
            // take occupation
            tb = (TextBox)CreateUserWizardStep1.ContentTemplateContainer.FindControl("txtOccupation");
            string occupation = tb.Text;
    
            // insert a row into USERS_PROFILE table
            SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
            con.Open();
            SqlCommand cmd = new SqlCommand("insert into users_profile values(@username, @fullname, @occupation)", con);
            cmd.Parameters.AddWithValue("@username", username);
            cmd.Parameters.AddWithValue("@fullname", fullname);
            cmd.Parameters.AddWithValue("@occupation", occupation);
            cmd.ExecuteNonQuery();
            con.Close();
    
            // upload photo to PHOTOS folder with <username>.jpg filename
            FileUpload fu = (FileUpload)CreateUserWizardStep1.ContentTemplateContainer.FindControl("FileUpload1");
            if (fu != null)
                fu.SaveAs(Request.MapPath("~/photos/" + username + ".jpg"));
        }
      
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <h2>Registration</h2>
        <asp:CreateUserWizard ID="CreateUserWizard1" runat="server" ActiveStepIndex="0" OnCreatedUser="CreateUserWizard1_CreatedUser">
            <WizardSteps>
                <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
                    <ContentTemplate>
                        <table border="0">
                            <tr>
                                <td align="center" colspan="2" style="font: 14pt arail">
                                    Account Details
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">User 
                                    Name:</asp:Label>
                                </td>
                                <td>
                                    <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName"
                                        ErrorMessage="User Name is required." ToolTip="User Name is required." ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password">Password:</asp:Label>
                                </td>
                                <td>
                                    <asp:TextBox ID="Password" runat="server" TextMode="Password"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"
                                        ErrorMessage="Password is required." ToolTip="Password is required." ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <asp:Label ID="ConfirmPasswordLabel" runat="server" AssociatedControlID="ConfirmPassword">Confirm Password:</asp:Label>
                                </td>
                                <td>
                                    <asp:TextBox ID="ConfirmPassword" runat="server" TextMode="Password"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="ConfirmPasswordRequired" runat="server" ControlToValidate="ConfirmPassword"
                                        ErrorMessage="Confirm Password is required." ToolTip="Confirm Password is required."
                                        ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">E-mail:</asp:Label>
                                </td>
                                <td>
                                    <asp:TextBox ID="Email" runat="server"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="EmailRequired" runat="server" ControlToValidate="Email"
                                        ErrorMessage="E-mail is required." ToolTip="E-mail is required." ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <asp:Label ID="QuestionLabel" runat="server" AssociatedControlID="Question">Security 
                                    Question:</asp:Label>
                                </td>
                                <td>
                                    <asp:TextBox ID="Question" runat="server"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="QuestionRequired" runat="server" ControlToValidate="Question"
                                        ErrorMessage="Security question is required." ToolTip="Security question is required."
                                        ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    <asp:Label ID="AnswerLabel" runat="server" AssociatedControlID="Answer">Security 
                                    Answer:</asp:Label>
                                </td>
                                <td>
                                    <asp:TextBox ID="Answer" runat="server"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="AnswerRequired" runat="server" ControlToValidate="Answer"
                                        ErrorMessage="Security answer is required." ToolTip="Security answer is required."
                                        ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="center" colspan="2" style="font: 14pt arail">
                                    Personal Details
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    Fullname
                                </td>
                                <td>
                                    <asp:TextBox ID="txtFullname" runat="server"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="FullnameRequired" runat="server" ControlToValidate="txtFullname"
                                        ErrorMessage="Fullname is requied!" ValidationGroup="CreateUserWizard1" ToolTip="Fullname Is Required">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    Occupation
                                </td>
                                <td>
                                    <asp:TextBox ID="txtOccupation" runat="server"></asp:TextBox>
                                    <asp:RequiredFieldValidator ID="OccupationRequired" runat="server" ControlToValidate="txtOccupation"
                                        ToolTip="Occupation Is Required" ValidationGroup="CreateUserWizard1" ErrorMessage="Occupation is requied!">*</asp:RequiredFieldValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="right">
                                    Select Photo
                                </td>
                                <td>
                                    <asp:FileUpload ID="FileUpload1" runat="server" />
                                </td>
                            </tr>
                            <tr>
                                <td align="center" colspan="2">
                                    <asp:CompareValidator ID="PasswordCompare" runat="server" ControlToCompare="Password"
                                        ControlToValidate="ConfirmPassword" Display="Dynamic" ErrorMessage="The Password and Confirmation Password must match."
                                        ValidationGroup="CreateUserWizard1"></asp:CompareValidator>
                                </td>
                            </tr>
                            <tr>
                                <td align="center" colspan="2" style="color: Red;">
                                    <asp:Literal ID="ErrorMessage" runat="server" EnableViewState="False"></asp:Literal>
                                </td>
                            </tr>
                        </table>
                        <p />
                    </ContentTemplate>
                </asp:CreateUserWizardStep>
                <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
                    <ContentTemplate>
                        <h3>
                            Your account has been successfully created
                        </h3>
                        <asp:Button ID="ContinueButton" runat="server" CausesValidation="False" CommandName="Continue"
                            Text="Continue" ValidationGroup="CreateUserWizard1" />
                    </ContentTemplate>
                </asp:CompleteWizardStep>
            </WizardSteps>
        </asp:CreateUserWizard>
        </form>
    </body>
    </html>
            
    
  15. Place Users class in App_Code folder and create GetUsers() and DeleteUser() methods as shown below.
    using System;
    using System.Collections;
    using System.Collections.Generic ;
    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.Configuration;
    using System.IO;
    
    public class Users
    {
        // returns a DataSet containing details of users from USERS_PROFILE table
        public DataSet GetUsers()  
        {
            SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
            SqlDataAdapter da = new SqlDataAdapter("select * from users_profile", con);
            DataSet ds = new DataSet();
            da.Fill(ds, "users");
            return ds;
        }
    
        // Deletes the user whose name is passed
        public void DeleteUser(String username)
        {
            SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
            con.Open();
            SqlCommand cmd = new SqlCommand("delete from users_profile where username = @username", con);
            cmd.Parameters.AddWithValue("@username", username);
            cmd.ExecuteNonQuery();
            con.Close();
     
            // remove user details from Membership tables
            Membership.DeleteUser(username);
    
            // delete file from PHOTOS folder
            File.Delete(HttpContext.Current.Server.MapPath("photos/" + username + ".jpg"));
       }
    }
            
    
    Note:Users.cs is used in default.aspx with ObjectDataSource.

  16. Go to design mode of Default.aspx and type Welcome message. Place LoginName control on the right. Then place  LoginStatus control. Place a Gridview and ObjectDataSource. Configure ObjectDataSource to use Users class with GetUsers() and DeleteUser() methods. Edit columns of GridView to customize them. Invoke Smart Tag of GridView and check Enable Deleting option. Add a new TemplateField to display photo of the user. You can see the complete code of Default.aspx below.
    <%@ Page Language="C#" %>
    <%@ Import Namespace= "System.Data.SqlClient" %>
    <%@ Import Namespace= "System.IO" %>
    <%@ Import Namespace = "System.Web.Configuration" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <script runat="server">
    </script>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Home Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
         <h3>Welcome [<asp:LoginName ID="LoginName1" runat="server" />] </h3>  
         <asp:LoginStatus ID="LoginStatus1" runat="server" />
         
         <h2>List Of Users</h2>
         <asp:GridView ID="GridView1" runat="server" DataSourceID="ObjectDataSource1" 
              DataKeyNames="username" AutoGenerateColumns="False" >
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                       <img src='photos/<%# Eval("username") %>.jpg'  width="100px" height="100px"/>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="username" HeaderText="username" 
                    SortExpression="username" />
                <asp:BoundField DataField="fullname" HeaderText="fullname" 
                    SortExpression="fullname" />
                <asp:BoundField DataField="occupation" HeaderText="occupation" 
                    SortExpression="occupation" />
                <asp:CommandField ShowDeleteButton="True" />
            </Columns>
        </asp:GridView>
      
         <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
             DeleteMethod="DeleteUser" SelectMethod="GetUsers" TypeName="Users">
             <DeleteParameters>
                 <asp:Parameter Name="username" Type="String" />
             </DeleteParameters>
         </asp:ObjectDataSource>
         
        </form>
    </body>
    </html>
            
    
  17. Web.config file in root directory is to be modified as follows to include connection string and other entries.
    <?xml version="1.0"?>
    <configuration>
    	<connectionStrings>
    		<add name="ConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\ASPNETDB.MDF;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient"/>
    	</connectionStrings>
    	<system.web>
    		<authorization>
    			<deny users="?"/>
    		</authorization>
    		<authentication mode="Forms" />
    		<compilation debug="true"/></system.web>
    </configuration>
            
    
Run login.aspx and click on link at the bottom to go to register.aspx. Enter data to register the user. Then log in to enter into default.aspx. You see the details of the users you created. Click on delete link to delete a user. Along with user even the photo placed in PHOTOS folder is also deleted (see code for DeleteUser() method in Users class).

You can customize login controls to a great extent. What i have shown here is a tip of the iceberg. So enojoy these controls.

Srikanth.