ASP.NET Login Control

I was attempting to write my first composite web control. In particular what I wanted to do was have a nice design-time UI and none of the examples I found on the web provided a proper design-time UI. So after much messing around I managed to write one and here it is, in a slightly simpler form.

So this control is really just a sample to show to how to write a composite web control and it may not be a very good example either since I'm still new to ASP.NET. But you might be able to use it or adapt it for you own purposes. There are two events that are of interest, Authenticate and Login.

In response to the Authenticate event you'll attempt to authenticate the user and return true if the authentication succeeded. If it fails the Message property of the event arguments should be set so a message can be displayed to the user.

The Login event is triggered if the Authenticate event has returned true and will generally be handled by redirecting the browser to a different URL.

using System;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Web.UI.Design;
using System.IO;

namespace Login
{
  /// <summary>Event arguments passed to the authenticate event handler</summary>
  public class AuthenticateEventArgs : EventArgs
  {
    /// <summary>Creates a new <see cref="AuthenticateEventArgs"/> instance.</summary>
    /// <param name="userName">Name of the user.</param>
    /// <param name="password">Password.</param>
    public AuthenticateEventArgs(string userName, string password)
    {
      this.userName = userName;
      this.password = password;
    }

    private string userName;
    /// <summary>Gets the name of the user.</summary>
    public string UserName
    {
      get { return userName; }
    }

    private string password;
    /// <summary>Gets the password.</summary>
    public string Password
    {
      get { return password; }
    }

    private string message;
    /// <summary>
    /// Gets or sets the message to display if the login failed.
    /// </summary>
    public string Message
    {
      get { return message; }
      set { message = value; }
    }
  }

  /// <summary>Event handler triggered to authenticate the user.</summary>
  public delegate bool AuthenticateEventHandler(object sender, AuthenticateEventArgs e);

  /// <summary>
  /// Control to handle logging in
  /// </summary>
  [Designer(typeof(Login.LoginControlDesigner))]
  public class LoginControl : WebControl, INamingContainer
  {
    private TextBox userNameEdit;
    private TextBox passwordEdit;
    private TableCell labelCell;
    private Table table;
    private Button loginButton;

    /// <summary>
    /// Add the child controls to the container, sizing it to the User's specifications.
    /// </summary>
    protected override void CreateChildControls()
    {
      table = new Table();
      table.Width = Unit.Percentage(100);

      // label row
      TableRow labelRow = new TableRow();
      table.Rows.Add(labelRow);
      labelCell = new TableCell();
      labelCell.Font.Bold = true;
      labelCell.HorizontalAlign = HorizontalAlign.Center;
      labelCell.Text = "Login";
      labelCell.ColumnSpan = 2;
      labelRow.Cells.Add(labelCell);

      // user name row
      TableRow userNameRow = new TableRow();
      table.Rows.Add(userNameRow);
      TableCell userNameLabelCell = new TableCell();
      userNameLabelCell.Text = "User name";
      userNameRow.Cells.Add(userNameLabelCell);
      TableCell userNameEditCell = new TableCell();
      userNameEdit = new TextBox();
      userNameEditCell.Controls.Add(userNameEdit);
      userNameRow.Cells.Add(userNameEditCell);

      // password row
      TableRow passwordRow = new TableRow();
      table.Rows.Add(passwordRow);
      TableCell passwordLabelCell = new TableCell();
      passwordLabelCell.Text = "Password";
      passwordRow.Cells.Add(passwordLabelCell);
      TableCell passwordEditCell = new TableCell();
      passwordEdit = new TextBox();
      passwordEdit.TextMode = TextBoxMode.Password;
      passwordEditCell.Controls.Add(passwordEdit);
      passwordRow.Cells.Add(passwordEditCell);

      // button row
      TableRow buttonRow = new TableRow();
      table.Rows.Add(buttonRow);
      TableCell buttonCell = new TableCell();
      buttonCell.ColumnSpan = 2;
      buttonCell.HorizontalAlign = HorizontalAlign.Center;
      loginButton = new Button();
      loginButton.Text = "Login";
      loginButton.Click += new EventHandler(loginButton_Click);
      buttonCell.Controls.Add(loginButton);
      buttonRow.Cells.Add(buttonCell);

      Controls.Add(table);
    }

    /// <summary>Event handler triggered to authenticate the user.</summary>
    public event AuthenticateEventHandler Authenticate;

    private void loginButton_Click(object sender, EventArgs e)
    {
      if (Authenticate != null)
      {
        AuthenticateEventArgs args = new AuthenticateEventArgs(userNameEdit.Text, passwordEdit.Text);
        if (Authenticate(this, args))
        {
          if (LoggedIn != null)
            LoggedIn(this, new EventArgs());
        }
        else
        {
          labelCell.Text = args.Message;
        }
      }
    }

    /// <summary> 
    /// Event triggered when the user successfully logs in.
    /// </summary>
    public event EventHandler LoggedIn;

    /// <summary> 
    /// Render the control at design-time.
    /// </summary>
    internal string DesignTimeRender()
    {
      EnsureChildControls();

      StringWriter sw = new StringWriter();
      HtmlTextWriter tw = new HtmlTextWriter(sw);

      RenderBeginTag(tw);
      RenderControl(tw);
      RenderEndTag(tw);

      return(sw.ToString());
    }

    /// <summary>
    /// Gets or sets the caption displayed in the login control.
    /// </summary>
    [Description("The caption displayed in the login control")]
    public string Caption
    {
      get
      {
        EnsureChildControls();
        return labelCell.Text;
      }
      set
      {
        EnsureChildControls();
        labelCell.Text = value;
      }
    }
  }

  /// <summary>
  /// Renders the control at design time.
  /// </summary>
  public class LoginControlDesigner : ControlDesigner
  {
    /// <summary>
    /// Returns a design view of the control as rendered by the control itself.
    /// </summary>
    /// <returns>The HTML of the design time control.</returns>
    public override string GetDesignTimeHtml()
    {
      LoginControl cb = (LoginControl) Component;
      return cb.DesignTimeRender();
    }
  }
}