The Main Menu

The main menu is contained in the Default.aspx page, and the code behind this page can be seen in Listing 22.1. Depending on the login type, the main menu contains either four or five buttons. The only variation is whether the Admin button is visible. If a user logs in, and her login account has administrative rights, the Admin button will be displayed.

The normal four buttons are for logging out, searching, managing files, and editing a user's profile. The main menu page can be seen in Figure 22.2.

Figure 22.2. The Main Screen Offers Four Choices.

graphics/22fig02.jpg

All of the button handler methods simply redirect to the appropriate page. The only addition to these methods is a call to the FormsAuthentication.SignOut() so that the user is logged out. The Page_Load() method takes a look at the Session variable named AccountType. If this variable is equal to one, the Admin button object's Visible property is set to true so that the button will appear in the menu.

Listing 22.1 Methods behind the default.aspx Page
 private void Page_Load(object sender, System.EventArgs e) {   if( Convert.ToInt32( Session["AccountType"] ) == 1 )   {     Admin.Visible = true;   } } private void LogOut_Click(object sender, System.EventArgs e) {   FormsAuthentication.SignOut();   Response.Redirect( "Login.aspx?Force=1" ); } private void Admin_Click(object sender, System.EventArgs e) {   Response.Redirect( "Admin.aspx" ); } private void Search_Click(object sender, System.EventArgs e) {   Response.Redirect( "Search.aspx" ); } private void Manage_Click(object sender, System.EventArgs e) {   Response.Redirect( "MngFiles.aspx" ); } private void Profile_Click(object sender, System.EventArgs e) {   Response.Redirect( "EditProfile.aspx" ); } 

Before a user even gets to the Default.aspx page containing the main menu, he must log in. That's because the application uses Forms authentication. The code for the login page can be seen in Listing 22.2, and the login page can be seen in operation in Figure 22.3.

Figure 22.3. When the Application First Appears, You'll Have to Log In.

graphics/22fig03.jpg

Here are the steps to use Forms authentication in this program:

  1. Edit the Web.Config file so that the application will know that you want Forms authentication, and what the login page is. (The name attribute of the Forms item is the name of the cookie that holds the authentication.) The following code shows how to do it:

     <authorization>   <deny users="?" /> </authorization> <authentication mode="Forms">   <forms name=".FILEREPOSITORY" loginUrl="login.aspx" protection="All"     timeout="30" path="/">   </forms> </authentication> 
  2. Create a login page, and if the user credentials are OK, use the following method to allow the user to be authenticated to the application:

     FormsAuthentication.RedirectFromLoginPage( strName,   RememberLogin.Checked ); 
  3. You can let the authentication time out after a period of nonuse, or you can offer the following method to let users explicitly logout:

     FormsAuthentication.SignOut(); 

The Page_Load() method shown in Listing 22.2 looks for a cookie that determines whether users can log on to the local computer automatically. First, though, it checks a parameter named Force to see whether the user is coming from another page and we need to force the user to log in. You see, if the user has just logged out by clicking the Logout button from the main menu, he doesn't want to come here and automatically just log in again. So from the Default.aspx page, when the user is redirected to this page, a parameter named Force will have a value of 1. If the value of the Force parameter is not 1, then the application will proceed to retrieve the Cookie normally. But if the Force parameter is missing or has a value other than 1, the user will not be logged in automatically.

If necessary, we attempt to retrieve a cookie to see whether we can automatically log in. We do this by creating an HttpCookie object named FileRepository with the following code:

 HttpCookie Cookie = Request.Cookies["FileRepository"]; 

If the cookie could not be retrieved (the case when the application runs for the first time), then the HttpCookie object will be null. In this case, we can't do an automatic login because we don't know if this is what the user wants, and more importantly we don't have the user credentials with which to do the login.

Let's say we got a cookie. Then we have to look at the value that determines whether the application should have remembered the name and password with which we'll populate the TextBox objects. This is done with the following code:

 bool bRemember = Convert.ToBoolean( Cookie.Values["Remember"] ); 

To determine whether we do an automatic login, we use the following code:

 bool bAutoLogin = Convert.ToBoolean( Cookie.Values["AutoLogin"] ); 

The name and password are retrieved from the cookie, and depending on the user preferences, either the user interface objects are populated with the name and password, the user is automatically logged in, or a normal login is presented to the user.

Listing 22.2 This Code Checks for a Cookie in Case It Needs to Retrieve a User Name and Password.
 private void Page_Load(object sender, System.EventArgs e) {   if( !IsPostBack )   {     int nForce = Convert.ToInt32( Request.QueryString["Force"] );     if( nForce != 1 )     {       HttpCookie Cookie = Request.Cookies["FileRepository"];       if( Cookie != null )       {         bool bRemember = Convert.ToBoolean( Cookie.Values["Remember"] );         bool bAutoLogin =           Convert.ToBoolean( Cookie.Values["AutoLogin"] );         string strName = Convert.ToString( Cookie.Values["Name"] );         string strPassword =           Convert.ToString( Cookie.Values["Password"] );         if( bAutoLogin )         {           FormsAuthentication.RedirectFromLoginPage( strName, true );         }         else if( bRemember )         {           Name.Text = strName;           Password.Text = strPassword;         }       }     }   } } 

If a user isn't automatically logged in, she'll have to type in her user name and password. It's possible that these two values will be filled in if the user has the Remember Password checkbox selected. Either way, though, she'll have to click the Log In button. Clicking this button fires the LogUserIn_Click() method that is shown in Listing 22.3.

The first thing that happens in the LogUserIn_Click() method is that a call to the LogUser() method is made. This method returns a value of 0 if the login was successful, 1 if the name couldn't be found, or 2 if the password didn't match. I've been told that you should never tell users if the password doesn't match because this tells them that they at least have entered a valid user name. Although this is probably valid criticism, I chose to leave the application functioning as it is. You could make the following change if you are worried:

Change:

C#

 if( nLogin == 0 ) {    . . . } else if( nLogin == 1 ) {   ErrorMessage.Text = "The Name/Password combination was incorrect."; } else if( nLogin == 2 ) {   ErrorMessage.Text = "The name you specified is already in use."; } 

VB

 If nLogin = 0 Then    . . . ElseIf nLogin = 1 Then   ErrorMessage.Text = "The Name/Password combination was incorrect." ElseIf nLogin = 2 Then   ErrorMessage.Text = "The name you specified is already in use." End If 
To:

C#

 if( nLogin == 0 ) {    . . . } else if( nLogin == 1 || nLogin == 2 ) {   ErrorMessage.Text = "The Name/Password combination was incorrect."; } 

VB

 If nLogin = 0 Then    . . . ElseIf nLogin = 1 OR nLogin = 2 Then   ErrorMessage.Text = "The Name/Password combination was incorrect." End If 

If the nLogin variable contains a 0 (meaning the login was successful), then the name and password are stored in local string variables. They're trimmed and made uppercase for easier handling. An HttpCookie object is created with the name FileRepository. The cookie has four values added: Name, Password, Remember (for Remember Login), and AutoLogin. The following line sets the cookie expiration date so that it never expires:

 Cookie.Expires = DateTime.MaxValue; 

Next, the cookie is added to the HTTP header by calling the Response.AppendCookie() method. Finally, a call to the FormsAuthentication.RedirectFromLoginPage() method is made. The user is now logged in and can access all of the application's pages. The user is redirected to the Default.aspx page, where the main menu is presented.

The LogUser() method can also be seen in Listing 22.3. This method performs the database access to validate the credentials that have been entered into the Name and Password TextBox objects.

The first thing the method does is to create a SqlConnection object the connection string is retrieved from the Web.Config file by using the ConfigurationSettings.AppSettings() method. A SqlData Reader object is declared and initialized to null (or Nothing in VB). Later in the code, a test for null (or Nothing) can be made to see whether the SqlDataReader object needs to be closed.

A string named strName is assigned the contents of the Name TextBox object. The data is trimmed (which removes leading and trailing blank spaces) and made uppercase for easier handling with the following line:

 string strName = Name.Text.Trim().ToUpper(); 

If the value in the Name field is 0 after it has been trimmed, then a valid user name hasn't been entered. In this case, the user is shown an error message, and the value of 3 is returned to the calling method. (Remember that the calling method acts only on return values of 0, 1, and 2.)

The password is retrieved from the Password TextBox object and stored in a string named strPassword. The data, though, is first trimmed and made uppercase.

A try/catch/finally construct is used to handle any exceptions that the database access methods may throw. The catch block simply sets the Label named ErrorMessage with the exception message text and returns a value of 3. The finally block closes the SqlDataReader object if it is not null (or Nothing), and closes the SqlConnection if it is open.

Inside of the try block, the operative code resides. The first thing that's done is to open the SqlConnection with the Open() method. A string containing the SQL is then created based on the name that is contained in the strName string variable. The following code shows how the SQL string is formed:

 "select * from Users where Name='" + strName + "'" 

If the user name is Suzy, the SQL will be the following:

 select * from Users where Name='Suzy' 

The SQL string isn't actually a string variable, but it's formed inside of a SqlCommand object's constructor. (Technically, at least one string is created by the common language runtime behind the scenes, and this is one of the considerations when optimizing this type of code.) Once the SqlCommand object has been created, a call to its ExecuteReader() method is made, which in turn returns a SqlDataReader object. If there are any records in the SqlDataReader object, the Read() method will return true otherwise it will return false (and this method will return a value of 1 indicating to the caller that the user name wasn't found). If a record was returned, we need to compare the password with what was typed in. If it matches, we're good to go, and this method returns a 0 to indicate success. If the password doesn't match, then the value of 2 is returned to indicate that the user name was found, but that the password is incorrect.

We've already talked about not revealing whether the password is incorrect, but simply telling users that the user name/password combination is incorrect. If you want to take this approach, you can simplify the code by letting the SQL match both the user name and password. If a record is returned, then the user name and password was found. If no records are returned, then the combination wasn't found. The following SQL statement creation can be used if you want to make this change:

C#
 "select * from Users where Name='" + strName +   "' and Password='" + strPassword + "'" 
VB
 "select * from Users where Name='" + strName + _   "' and Password='" + strPassword + "'" 

If the name is found and the NewUser CheckBox object is checked, an error message is shown and the value of 3 is returned. That's because we don't want to create a new user who has a duplicate name that already exists in the database.

If the name and password matches, some other information is stored in session variables. The user ID, name, and account type are all stored for later use.

If no record was found that matches the user name, and the NewUser CheckBox object is selected, then a new user record needs to be created. If you've used the application, you've probably seen a table appear when you click the New User checkbox. This table allows the user to enter his date of birth and his e-mail address. The code to hide and show the table can be seen in the NewUser_CheckChanged() method shown in Listing 22.3. This method also changes the state of the RememberLogin and AutoLogin objects to appropriate values.

The table object is named ExtraInfoTable, and it has two child objects that are TextBox objects. These objects can't be used directly because they are child objects of the table. To get references to the TextBox objects, we use the FindControl() method. The following line of code gets an object reference to a TextBox control named Email:

 TextBox tb = (TextBox) ExtraInfoTable.FindControl("Email"); 

The e-mail and date-of-birth information is retrieved from the TextBox child objects, and they are trimmed in case there are unwanted blank spaces. A SqlCommand object is created with a SQL string that will insert the new row into the Users table. This is the SQL string creation code:

C#
 "Insert into " +   "Users (Name,Password,Email,DateOfBirth) VALUES ('" +   strName + "','" + strPassword + "','" + strEmail + "','" +     strDateOfBirth + "') select @ID=@@IDENTITY" 
VB
 "Insert into " + _   "Users (Name,Password,Email,DateOfBirth) VALUES ('" + _   strName + "','" + strPassword + "','" + strEmail + "','" + _     strDateOfBirth + "') select @ID=@@IDENTITY" 

We'll need to add a parameter named @ID to the SqlCommand object. This is so that we can take advantage of the special SQL that gets the identity value and puts it into the variable named @ID. This value will be the newly created user ID. Once the ExecuteNonQuery() method is called, the SqlCommand parameter will contain the ID value.

Listing 22.3 LoginUser_Click() Is Fired When the Log In Button Is Clicked. The LogUser() Method Does the Work of Trying to Log a User In.
 private void LogUserIn_Click(object sender, System.EventArgs e) {   // Call the LoginUser() method that does the   //   database access.   int nLogin = LogUser();   // If the returned value is 0, their credentials check out.   if( nLogin == 0 )   {     // Get a cleaned version of the name and password.     string strName = Name.Text.Trim().ToUpper();     string strPassword = Password.Text.Trim().ToUpper();     // Create a cookie and set the values that need to be saved.     HttpCookie Cookie = new HttpCookie( "FileRepository" );     Cookie.Values.Add( "Name", strName );     Cookie.Values.Add( "Password", strPassword );     Cookie.Values.Add( "Remember",         Convert.ToString( RememberLogin.Checked ) );     Cookie.Values.Add( "AutoLogin",         Convert.ToString( AutoLogin.Checked ) );     Cookie.Expires = DateTime.MaxValue;     Response.AppendCookie( Cookie );     // Do the actual authentication.     FormsAuthentication.RedirectFromLoginPage( strName,        RememberLogin.Checked );   }   // Login failure.   else if( nLogin == 1 )   {     ErrorMessage.Text = "The Name/Password combination was incorrect.";   }   // They tried to create a new account with a duplicate name.   else if( nLogin == 2 )   {     ErrorMessage.Text = "The name you specified is already in use.";   } } // This method scrubs the ' character. string SafeSql( string sql ) {     Regex regex = new Regex("'");     return regex.Replace(sql, "''");  } // This method does the database access to match name and password. private int LogUser() {   // Create the connection object.   SqlConnection objConnection =   new SqlConnection(ConfigurationSettings.AppSettings["ConnectString"]);   // Declare a null SqlDataReader.   SqlDataReader objReader = null;   // Get a cleaned name,   string strName = Name.Text.Trim().ToUpper();   // Bail out if they entered no valid name.   if( strName.Length == 0 )   {     ErrorMessage.Text = "You must have at least one non-blank " +       "character in the name field.";     return( 3 );   }   // Get a cleaned password.   string strPassword = Password.Text.Trim().ToUpper();   int nRet = 0;   try   {     // Open the connection.     objConnection.Open();     // Create a command object.     SqlCommand objCommand =       new SqlCommand( "select * from Users where Name='" +       SafeSql( strName ) +       "'", objConnection );     // Get a recordset.     objReader = objCommand.ExecuteReader();     // If there are records, perform this code.     if( objReader.Read() )     {       // First see if they specified that this is a new user.       if( NewUser.Checked )       {         ErrorMessage.Text = "You tried to create a user that " +           "already exists.";         return( 3 );       }       else       {         // Compare the entered password with the password         //   from the database.         if( strPassword !=           Convert.ToString( objReader["Password"] ).ToUpper() )         {           nRet = 1;         }         else         {           // Set the session variables to contain user ID, name,           //   and account type.           Session["ID"] = Convert.ToInt32( objReader["ID"] );           Session["Name"] = Convert.ToString( objReader["Name"] );           Session["AccountType"] =             Convert.ToInt32( objReader["AccountType"] );         }       }     }     else     {       // Here we come to create a new user record.       if( NewUser.Checked )       {         // Close the reader.         objReader.Close();         // Get the extra information which includes         //   the email and date of birth.         TextBox tb = (TextBox) ExtraInfoTable.FindControl("Email");         string strEmail = tb.Text.Trim();         tb = (TextBox) ExtraInfoTable.FindControl("DateOfBirth");         string strDateOfBirth = tb.Text.Trim();         // Create a command object.         objCommand = new SqlCommand( "Insert into " +             "Users (Name,Password,Email,DateOfBirth) VALUES ('" +             SafeSql( strName ) + "','" + SafeSql( strPassword ) +             "','" + SafeSql( strEmail ) + "','" +             SafeSql( strDateOfBirth ) +             "') select @ID=@@IDENTITY", objConnection);         // Add the ID as a parameter.         objCommand.Parameters.Add( "@ID", SqlDbType.Int );         objCommand.Parameters["@ID"].Direction =             ParameterDirection.Output;         // Execute the query.         objCommand.ExecuteNonQuery();         // Store the user ID, name, and account type in session         //   variables.         Session["ID"] =             Convert.ToInt32( objCommand.Parameters["@ID"].Value );         Session["Name"] = strName;         Session["AccountType"] = 0;       }       else       {         nRet = 1;       }     }   }   catch( Exception ex )   {     // Alert the user to the error.     ErrorMessage.Text = ex.Message.ToString();     nRet = 3;   }   finally   {     // Close the reader.     if( objReader != null )     {       objReader.Close();     }     // Close the connection.     if( objConnection.State == ConnectionState.Open )     {       objConnection.Close();     }   }   return( nRet ); } // This method changes the extra information user interface objects. //   When the check box is selected the extra objects appear, otherwise //   they are hidden. private void NewUser_CheckedChanged(object sender, System.EventArgs e) {   if( NewUser.Checked )   {     RememberLogin.Checked = false;     RememberLogin.Enabled = false;     AutoLogin.Checked = false;     AutoLogin.Enabled = false;     ExtraInfoTable.Visible = true;   }   else   {     RememberLogin.Enabled = true;     AutoLogin.Enabled = true;     ExtraInfoTable.Visible = false;   } } 


ASP. NET Solutions - 24 Case Studies. Best Practices for Developers
ASP. NET Solutions - 24 Case Studies. Best Practices for Developers
ISBN: 321159659
EAN: N/A
Year: 2003
Pages: 175

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net