Posted on March 13, 2008 15:03 by mcollins

Note to self: fully test out all features of your code before publishing it in a blog with a major defect.

This morning I posted my Login adapter code, and in theory my post was correct because it did correctly render my Login control in a CSS-friendly format.  The one test that I failed to run completely at the time was to perform an actual login and make sure that it worked correctly.  The negative case did work, but on the computer that I wrote the article on, I didn't have a good membership database so I expected it to fail.  But when I expected the login to succeed...I learned my lesson during lunch when I was playing with the adapter again.

The problem with the earlier version of my CSS adapter has to do with how the Login control does it's template.  When using an adapter, the Login control does not seem to get access to the UserName, Password, RememberMe, or FailureText fields in my custom template.  Therefore, when the Login control posts back, I needed to move the UserName, Password, and RememberMe values back to the Login control for authentication to occur correctly.  This leads to a problem: the Login.UserName and Login.RememberMeSet properties are read/write, but the Login.Password property is read-only.  Therefore, there's no way to pass the password to the Login control to perform authentication.

To solve this, with the help of Reflector,  I needed to modify the adapter to implement the authentication logic for the Login control.  I did this by adding an event handler for the Login.Authenticate event.  During the login process, the Login control will look to see if there are any event handlers attached to the Login.Authenticate event.  If there are, then the Login control will use the event handler to perform the authentication.  If not, then the Login control will use the ASP.NET membership providers to perform the authentication.  While I want to use the ASP.NET membership provider, it became clear to me that because I could not propagate the password to the Login control, I had to implement the authentication mechanism on my own using an event handler.

One other enhancement that I made to this latest code is that I overrode the WebControlAdapter.Render method in my LoginAdapter class to check to see if the Login.VisibleWhenLoggedIn property is set.  If the Login control is on a page where the user is authenticated, then the LoginAdapter class will skip rendering the Login control.

This time I tested both positive and negative login scenarios, so I'm pretty positive that it will authenticate the user as well as render CSS-friendly HTML.  Here's the code:

   1: using System;
   2: using System.Diagnostics;
   3: using System.Diagnostics.CodeAnalysis;
   4: using System.Web.Security;
   5: using System.Web.UI;
   6: using System.Web.UI.HtmlControls;
   7: using System.Web.UI.WebControls;
   8: using System.Web.UI.WebControls.Adapters;
   9:  
  10: /// <summary>
  11: /// Implements a custom control adapter for the ASP.NET <see cref="Login"/>
  12: /// control that produces CSS-friendly HTML.
  13: /// </summary>
  14: public class LoginAdapter : WebControlAdapter {
  15:     /// <summary>
  16:     /// The container <see cref="Control"/> that contains the
  17:     /// <see cref="Login"/> control's template.
  18:     /// </summary>
  19:     private Control container;
  20:  
  21:     /// <summary>
  22:     /// The value entered into the password text box.
  23:     /// </summary>
  24:     private string passwordValue;
  25:  
  26:     /// <summary>
  27:     /// The value of the remember me check box.
  28:     /// </summary>
  29:     private bool rememberMeValue;
  30:  
  31:     /// <summary>
  32:     /// The value entered into the user name text box.
  33:     /// </summary>
  34:     private string userNameValue;
  35:  
  36:     /// <summary>
  37:     /// Creates the child controls for the <see cref="Login"/> control.
  38:     /// </summary>
  39:     protected override void CreateChildControls() {
  40:         base.CreateChildControls();
  41:  
  42:         Login login = Control as Login;
  43:         Debug.Assert(login != null, "login != null");
  44:  
  45:         ITemplate layoutTemplate = login.LayoutTemplate;
  46:         if (layoutTemplate == null) {
  47:             layoutTemplate = new DefaultLoginTemplate(login);
  48:         }
  49:  
  50:         container = new Control();
  51:         layoutTemplate.InstantiateIn(container);
  52:         login.Controls.Clear();
  53:         login.Controls.Add(container);
  54:  
  55:         IEditableTextControl userName = container.FindControl("UserName") as
  56:             IEditableTextControl;
  57:         Debug.Assert(userName != null, "userName != null");
  58:         userName.TextChanged += UserName_TextChanged;
  59:  
  60:         IEditableTextControl password = container.FindControl("Password") as
  61:             IEditableTextControl;
  62:         Debug.Assert(password != null, "password != null");
  63:         password.TextChanged += Password_TextChanged;
  64:  
  65:         ICheckBoxControl rememberMe = container.FindControl("RememberMe") as
  66:             ICheckBoxControl;
  67:         Debug.Assert(rememberMe != null, "rememberMe != null");
  68:         rememberMe.CheckedChanged += RememberMe_CheckedChanged;
  69:     }
  70:  
  71:     /// <summary>
  72:     /// Creates the child controls that will be used to render the
  73:     /// contents of the <see cref="Login"/> control.
  74:     /// </summary>
  75:     /// <param name="e">The event arguments.</param>
  76:     protected override void OnInit(EventArgs e) {
  77:         base.OnInit(e);
  78:  
  79:         Login login = Control as Login;
  80:         Debug.Assert(login != null, "login != null");
  81:         login.Authenticate += login_Authenticate;
  82:         login.LoginError += login_LoginError;
  83:     }
  84:  
  85:     /// <summary>
  86:     /// Sets the text and check box settings for the user name, password,
  87:     /// and remember me fields on the login form.
  88:     /// </summary>
  89:     /// <param name="e">The event arguments.</param>
  90:     protected override void OnLoad(EventArgs e) {
  91:         base.OnLoad(e);
  92:  
  93:         if (!Page.IsPostBack) {
  94:             Login login = Control as Login;
  95:             Debug.Assert(login != null, "login != null");
  96:  
  97:             userNameValue = login.UserName;
  98:             passwordValue = "";
  99:             rememberMeValue = login.RememberMeSet;
 100:         }
 101:     }
 102:  
 103:     /// <summary>
 104:     /// Sets the value of the user name text box and the remember me
 105:     /// checkbox before the control is rendered.
 106:     /// </summary>
 107:     /// <param name="e"></param>
 108:     protected override void OnPreRender(EventArgs e) {
 109:         IEditableTextControl userName = container.FindControl("UserName") as
 110:             IEditableTextControl;
 111:         Debug.Assert(userName != null, "userName != null");
 112:         userName.Text = userNameValue;
 113:  
 114:         IEditableTextControl password = container.FindControl("Password") as
 115:             IEditableTextControl;
 116:         Debug.Assert(password != null, "password != null");
 117:         password.Text = "";
 118:  
 119:         ICheckBoxControl rememberMe = container.FindControl("RememberMe") as
 120:             ICheckBoxControl;
 121:         Debug.Assert(rememberMe != null, "rememberMe != null");
 122:         rememberMe.Checked = rememberMeValue;
 123:     }
 124:  
 125:     /// <summary>
 126:     /// Detaches the adapter from the <see cref="Login.LoginError"/> event.
 127:     /// </summary>
 128:     /// <param name="e">The event arguments.</param>
 129:     protected override void OnUnload(EventArgs e) {
 130:         Login login = Control as Login;
 131:         Debug.Assert(login != null, "login != null");
 132:         login.Authenticate -= login_Authenticate;
 133:         login.LoginError -= login_LoginError;
 134:  
 135:         IEditableTextControl userName = container.FindControl("UserName") as
 136:             IEditableTextControl;
 137:         Debug.Assert(userName != null, "userName != null");
 138:         userName.TextChanged -= UserName_TextChanged;
 139:  
 140:         IEditableTextControl password = container.FindControl("Password") as
 141:             IEditableTextControl;
 142:         Debug.Assert(password != null, "password != null");
 143:         password.TextChanged -= Password_TextChanged;
 144:  
 145:         ICheckBoxControl rememberMe = container.FindControl("RememberMe") as
 146:             ICheckBoxControl;
 147:         Debug.Assert(rememberMe != null, "rememberMe != null");
 148:         rememberMe.CheckedChanged -= RememberMe_CheckedChanged;
 149:  
 150:         base.OnUnload(e);
 151:     }
 152:  
 153:     /// <summary>
 154:     /// Prevents the login control from rendering if the user is
 155:     /// authenticated and the <see cref="Login.VisibleWhenLoggedIn"/>
 156:     /// property is set to false.
 157:     /// </summary>
 158:     /// <param name="writer">
 159:     /// The <see cref="HtmlTextWriter"/> object to use to render the
 160:     /// <see cref="Login"/> control.
 161:     /// </param>
 162:     protected override void Render(HtmlTextWriter writer) {
 163:         Login login = Control as Login;
 164:         Debug.Assert(login != null, "login != null");
 165:  
 166:         if (!Page.Request.IsAuthenticated || login.VisibleWhenLoggedIn) {
 167:             base.Render(writer);
 168:         }
 169:     }
 170:  
 171:     /// <summary>
 172:     /// Renders the opening tag that encapsulates the <see cref="Login"/>
 173:     /// control's content.
 174:     /// </summary>
 175:     /// <param name="writer">
 176:     /// The <see cref="HtmlTextWriter"/> object to use to output the
 177:     /// opening tag for the control.
 178:     /// </param>
 179:     protected override void RenderBeginTag(HtmlTextWriter writer) {
 180:         Login login = Control as Login;
 181:         Debug.Assert(login != null, "login != null");
 182:  
 183:         writer.AddAttribute(HtmlTextWriterAttribute.Id, login.ClientID);
 184:  
 185:         if (!login.ControlStyle.IsEmpty) {
 186:             if (!String.IsNullOrEmpty(login.ControlStyle.CssClass)) {
 187:                 writer.AddAttribute(HtmlTextWriterAttribute.Class,
 188:                     login.ControlStyle.CssClass);
 189:             }
 190:  
 191:             foreach (string key in login.Style.Keys) {
 192:                 writer.AddStyleAttribute(key, login.Style[key]);
 193:             }
 194:         }
 195:  
 196:         writer.RenderBeginTag(HtmlTextWriterTag.Div);
 197:     }
 198:  
 199:     /// <summary>
 200:     /// Renders the inner contents of the <see cref="Login"/> control.
 201:     /// </summary>
 202:     /// <param name="writer">
 203:     /// The <see cref="HtmlTextWriter"/> object to use to output the
 204:     /// control's contents.
 205:     /// </param>
 206:     protected override void RenderContents(HtmlTextWriter writer) {
 207:         container.RenderControl(writer);
 208:     }
 209:  
 210:     /// <summary>
 211:     /// Renders the closing outer tag for the <see cref="Login"/> control.
 212:     /// </summary>
 213:     /// <param name="writer">
 214:     /// The <see cref="HtmlTextWriter"/> object to use to output the
 215:     /// control's contents.
 216:     /// </param>
 217:     protected override void RenderEndTag(HtmlTextWriter writer) {
 218:         writer.RenderEndTag();
 219:     }
 220:  
 221:     /// <summary>
 222:     /// Authenticates the user using the ASP.NET membership provider.
 223:     /// </summary>
 224:     /// <param name="sender">The <see cref="Login"/> control.</param>
 225:     /// <param name="e">The event arguments.</param>
 226:     private void login_Authenticate(object sender, AuthenticateEventArgs e) {
 227:         Login login = sender as Login;
 228:         Debug.Assert(login != null, "login != null");
 229:  
 230:         MembershipProvider provider;
 231:         string providerName = login.MembershipProvider;
 232:         if (!String.IsNullOrEmpty(providerName)) {
 233:             provider = Membership.Providers[providerName];
 234:         } else {
 235:             provider = Membership.Provider;
 236:         }
 237:  
 238:         e.Authenticated = provider.ValidateUser(userNameValue,
 239:             passwordValue);
 240:     }
 241:  
 242:     /// <summary>
 243:     /// Displays the failure text in the <see cref="Login"/> control's
 244:     /// output if a login error occurred.
 245:     /// </summary>
 246:     /// <param name="sender">The <see cref="Login"/> control.</param>
 247:     /// <param name="e">The event arguments.</param>
 248:     private void login_LoginError(object sender, EventArgs e) {
 249:         Login login = Control as Login;
 250:         Debug.Assert(login != null, "login != null");
 251:  
 252:         ITextControl failureText = container.FindControl("FailureText") as
 253:             ITextControl;
 254:         Debug.Assert(failureText != null, "failureText != null");
 255:         failureText.Text = login.FailureText;
 256:  
 257:         Control parent = ((Control)failureText).Parent;
 258:         if (!parent.Visible) {
 259:             parent.Visible = true;
 260:         }
 261:     }
 262:  
 263:     /// <summary>
 264:     /// Called when the value in the password text box has been changed.
 265:     /// </summary>
 266:     /// <param name="sender">
 267:     /// The <see cref="IEditableTextControl"/> object.
 268:     /// </param>
 269:     /// <param name="e">The event arguments.</param>
 270:     private void Password_TextChanged(object sender, EventArgs e) {
 271:         IEditableTextControl password = sender as IEditableTextControl;
 272:         Debug.Assert(password != null, "password != null");
 273:         passwordValue = password.Text;
 274:     }
 275:  
 276:     /// <summary>
 277:     /// Called when the check box status for the remember me check box
 278:     /// has been changed.
 279:     /// </summary>
 280:     /// <param name="sender">
 281:     /// The <see cref="ICheckBoxControl"/> object.
 282:     /// </param>
 283:     /// <param name="e">The event arguments.</param>
 284:     private void RememberMe_CheckedChanged(object sender, EventArgs e) {
 285:         ICheckBoxControl rememberMe = sender as ICheckBoxControl;
 286:         Debug.Assert(rememberMe != null, "rememberMe != null");
 287:         rememberMeValue = rememberMe.Checked;
 288:  
 289:         Login login = Control as Login;
 290:         Debug.Assert(login != null, "login != null");
 291:         login.RememberMeSet = rememberMeValue;
 292:     }
 293:  
 294:     /// <summary>
 295:     /// Called when the value in the user name text box has been changed.
 296:     /// </summary>
 297:     /// <param name="sender">
 298:     /// The <see cref="IEditableTextControl"/> object.
 299:     /// </param>
 300:     /// <param name="e">The event arguments.</param>
 301:     private void UserName_TextChanged(object sender, EventArgs e) {
 302:         IEditableTextControl userName = sender as IEditableTextControl;
 303:         Debug.Assert(userName != null, "userName != null");
 304:         userNameValue = userName.Text;
 305:     }
 306:  
 307:     /// <summary>
 308:     /// Implements the default template for the <see cref="Login"/> control.
 309:     /// </summary>
 310:     private class DefaultLoginTemplate : ITemplate {
 311:         /// <summary>
 312:         /// The <see cref="Login"/> control that the template is a template
 313:         /// for.
 314:         /// </summary>
 315:         private Login login;
 316:  
 317:         /// <summary>
 318:         /// Constructs a new <see cref="DefaultLoginTemplate"/> object.
 319:         /// </summary>
 320:         /// <param name="login">
 321:         /// The <see cref="Login"/> control that the template is a template
 322:         /// for.
 323:         /// </param>
 324:         public DefaultLoginTemplate(Login login) {
 325:             this.login = login;
 326:         }
 327:  
 328:         /// <summary>
 329:         /// Adds the standard <see cref="Login"/> controls to the template
 330:         /// container.
 331:         /// </summary>
 332:         /// <param name="container">
 333:         /// The parent container that the controls will be added to as
 334:         /// children.
 335:         /// </param>
 336:         public void InstantiateIn(Control container) {
 337:             CreateTitleControl(container);
 338:             CreateInstructionControl(container);
 339:             CreateFailureControl(container);
 340:             CreateUserInformationFieldSet(container);
 341:             CreateOptionsFieldSet(container);
 342:             CreateLoginButton(container);
 343:             CreateLinks(container);
 344:         }
 345:  
 346:         /// <summary>
 347:         /// Creates the controls used to render the link to create a new
 348:         /// user account.
 349:         /// </summary>
 350:         /// <param name="hasCreateUserIconUrl">
 351:         /// True if the icon should be rendered.
 352:         /// </param>
 353:         /// <param name="hasCreateUserText">
 354:         /// True if the link text should be rendered.
 355:         /// </param>
 356:         /// <returns>The link.</returns>
 357:         private Control CreateCreateUserLink(bool hasCreateUserIconUrl, 
 358:             bool hasCreateUserText) {
 359:             var listItem = new HtmlGenericControl("LI") {
 360:                 EnableViewState = false
 361:             };
 362:  
 363:             var link = new HyperLink() {
 364:                 EnableViewState = false,
 365:                 NavigateUrl = login.CreateUserUrl
 366:             };
 367:             link.MergeStyle(login.HyperLinkStyle);
 368:             listItem.Controls.Add(link);
 369:  
 370:             if (hasCreateUserIconUrl) {
 371:                 var image = new Image() {
 372:                     EnableViewState = false,
 373:                     ImageUrl = login.CreateUserIconUrl
 374:                 };
 375:                 link.Controls.Add(image);
 376:             }
 377:             if (hasCreateUserText) {
 378:                 var text = new Literal() {
 379:                     Text = login.CreateUserText
 380:                 };
 381:                 link.Controls.Add(text);
 382:             }
 383:  
 384:             return listItem;
 385:         }
 386:  
 387:         /// <summary>
 388:         /// Creates the controls that are used to render the failure message
 389:         /// for the <see cref="Login"/> control.
 390:         /// </summary>
 391:         /// <param name="container">
 392:         /// The parent container <see cref="Control"/> that the new control
 393:         /// is to be added to.
 394:         /// </param>
 395:         private void CreateFailureControl(Control container) {
 396:             var failureTextDiv = new HtmlGenericControl("DIV") {
 397:                 EnableViewState = false,
 398:                 Visible = false
 399:             };
 400:             SetCssStyles(failureTextDiv, login.FailureTextStyle);
 401:             container.Controls.Add(failureTextDiv);
 402:  
 403:             var failureText = new Literal {
 404:                 EnableViewState = false,
 405:                 ID = "FailureText"
 406:             };
 407:             failureTextDiv.Controls.Add(failureText);
 408:         }
 409:  
 410:         /// <summary>
 411:         /// Creates the controls used to render the link to navigate to a
 412:         /// help page for the login form.
 413:         /// </summary>
 414:         /// <param name="hasCreateUserIconUrl">
 415:         /// True if the icon should be rendered.
 416:         /// </param>
 417:         /// <param name="hasCreateUserText">
 418:         /// True if the link text should be rendered.
 419:         /// </param>
 420:         /// <returns>The link.</returns>
 421:         private Control CreateHelpPageLink(bool hasHelpPageIconUrl, 
 422:             bool hasHelpPageText) {
 423:             var listItem = new HtmlGenericControl("LI") {
 424:                 EnableViewState = false
 425:             };
 426:  
 427:             var link = new HyperLink() {
 428:                 EnableViewState = false,
 429:                 NavigateUrl = login.HelpPageUrl
 430:             };
 431:             link.MergeStyle(login.HyperLinkStyle);
 432:             listItem.Controls.Add(link);
 433:  
 434:             if (hasHelpPageIconUrl) {
 435:                 var image = new Image() {
 436:                     EnableViewState = false,
 437:                     ImageUrl = login.HelpPageIconUrl
 438:                 };
 439:                 link.Controls.Add(image);
 440:             }
 441:             if (hasHelpPageText) {
 442:                 var text = new Literal() {
 443:                     Text = login.HelpPageText
 444:                 };
 445:                 link.Controls.Add(text);
 446:             }
 447:  
 448:             return listItem;
 449:         }
 450:  
 451:         /// <summary>
 452:         /// Creates the controls that are used to render the instructions
 453:         /// for the <see cref="Login"/> control.
 454:         /// </summary>
 455:         /// <param name="container">
 456:         /// The parent container <see cref="Control"/> that the new control
 457:         /// is to be added to.
 458:         /// </param>
 459:         private void CreateInstructionControl(Control container) {
 460:             var instructions = new HtmlGenericControl("DIV") {
 461:                 EnableViewState = false,
 462:                 InnerHtml = login.InstructionText
 463:             };
 464:             SetCssStyles(instructions, login.InstructionTextStyle);
 465:             container.Controls.Add(instructions);
 466:         }
 467:  
 468:         /// <summary>
 469:         /// Creates the controls used to render helpful links to other pages.
 470:         /// </summary>
 471:         /// <param name="container">
 472:         /// The parent container <see cref="Control"/> that the new control
 473:         /// is to be added to.
 474:         /// </param>
 475:         private void CreateLinks(Control container) {
 476:             bool hasCreateUserIconUrl =
 477:                 !String.IsNullOrEmpty(login.CreateUserIconUrl);
 478:             bool hasCreateUserText =
 479:                 !String.IsNullOrEmpty(login.CreateUserText);
 480:             bool hasCreateUserLink = hasCreateUserIconUrl || hasCreateUserText;
 481:             bool hasPasswordRecoveryIconUrl =
 482:                 !String.IsNullOrEmpty(login.PasswordRecoveryIconUrl);
 483:             bool hasPasswordRecoveryText =
 484:                 !String.IsNullOrEmpty(login.PasswordRecoveryText);
 485:             bool hasPasswordRecoveryLink = hasPasswordRecoveryIconUrl ||
 486:                 hasPasswordRecoveryText;
 487:             bool hasHelpPageIconUrl =
 488:                 !String.IsNullOrEmpty(login.HelpPageIconUrl);
 489:             bool hasHelpPageText = !String.IsNullOrEmpty(login.HelpPageText);
 490:             bool hasHelpLink = hasHelpPageIconUrl || hasHelpPageText;
 491:             if (hasCreateUserLink || hasPasswordRecoveryLink || hasHelpLink) {
 492:                 var linkList = new HtmlGenericControl("UL") {
 493:                     EnableViewState = false
 494:                 };
 495:                 container.Controls.Add(linkList);
 496:  
 497:                 if (hasCreateUserLink) {
 498:                     linkList.Controls.Add(CreateCreateUserLink(
 499:                         hasCreateUserIconUrl, hasCreateUserText));
 500:                 }
 501:                 if (hasPasswordRecoveryLink) {
 502:                     linkList.Controls.Add(CreatePasswordRecoveryLink(
 503:                         hasPasswordRecoveryIconUrl, hasPasswordRecoveryText));
 504:                 }
 505:                 if (hasHelpLink) {
 506:                     linkList.Controls.Add(CreateHelpPageLink(
 507:                         hasHelpPageIconUrl, hasHelpPageText));
 508:                 }
 509:             }
 510:         }
 511:  
 512:         /// <summary>
 513:         /// Creates the <see cref="Button"/> control used to initiate the
 514:         /// login process.
 515:         /// </summary>
 516:         /// <param name="container">
 517:         /// The parent container <see cref="Control"/> that the new control
 518:         /// is to be added to.
 519:         /// </param>
 520:         private void CreateLoginButton(Control container) {
 521:             var loginButton = new Button {
 522:                 CommandName = "Login",
 523:                 EnableViewState = false,
 524:                 ID = "LoginButton",
 525:                 Text = login.LoginButtonText,
 526:                 ValidationGroup = login.ID
 527:             };
 528:             container.Controls.Add(loginButton);
 529:         }
 530:  
 531:         /// <summary>
 532:         /// Creates the controls that are used to render the
 533:         /// &lt;FIELDSET&gt; containing authentication options.
 534:         /// </summary>
 535:         /// <param name="container">
 536:         /// The parent container <see cref="Control"/> that the new control
 537:         /// is to be added to.
 538:         /// </param>
 539:         private void CreateOptionsFieldSet(Control container) {
 540:             var rememberMeFieldSet = new HtmlGenericControl("FIELDSET") {
 541:                 EnableViewState = false,
 542:                 ID = "RememberMeFieldSet"
 543:             };
 544:             container.Controls.Add(rememberMeFieldSet);
 545:  
 546:             HtmlGenericControl rememberMeLegend =
 547:                 new HtmlGenericControl("LEGEND") {
 548:                     EnableViewState = false,
 549:                     InnerText = "Options"
 550:                 };
 551:             rememberMeFieldSet.Controls.Add(rememberMeLegend);
 552:  
 553:             var rememberMe = new CheckBox {
 554:                 EnableViewState = false,
 555:                 ID = "RememberMe",
 556:                 Text = login.RememberMeText
 557:             };
 558:             rememberMe.MergeStyle(login.CheckBoxStyle);
 559:             rememberMeFieldSet.Controls.Add(rememberMe);
 560:         }
 561:  
 562:         /// <summary>
 563:         /// Creates the controls used to capture the user's password.
 564:         /// </summary>
 565:         /// <param name="container">
 566:         /// The container <see cref="Control"/> that the password controls
 567:         /// will be added to.
 568:         /// </param>
 569:         private void CreatePasswordControls(Control container) {
 570:             var passwordLabel = new Label {
 571:                 AssociatedControlID = "Password",
 572:                 EnableViewState = false,
 573:                 ID = "PasswordLabel",
 574:                 Text = login.PasswordLabelText
 575:             };
 576:             passwordLabel.MergeStyle(login.LabelStyle);
 577:             container.Controls.Add(passwordLabel);
 578:  
 579:             var password = new TextBox {
 580:                 ID = "Password",
 581:                 TextMode = TextBoxMode.Password
 582:             };
 583:             password.MergeStyle(login.TextBoxStyle);
 584:             container.Controls.Add(password);
 585:  
 586:             var passwordValidator = new RequiredFieldValidator {
 587:                 ControlToValidate = "Password",
 588:                 EnableViewState = false,
 589:                 ID = "PasswordRequired",
 590:                 Text = login.PasswordRequiredErrorMessage,
 591:                 ToolTip = login.PasswordRequiredErrorMessage,
 592:                 ValidationGroup = login.ID
 593:             };
 594:             passwordValidator.MergeStyle(login.ValidatorTextStyle);
 595:             container.Controls.Add(passwordValidator);
 596:         }
 597:  
 598:         /// <summary>
 599:         /// Creates the controls used to render the link to recover a
 600:         /// lost password.
 601:         /// </summary>
 602:         /// <param name="hasCreateUserIconUrl">
 603:         /// True if the icon should be rendered.
 604:         /// </param>
 605:         /// <param name="hasCreateUserText">
 606:         /// True if the link text should be rendered.
 607:         /// </param>
 608:         /// <returns>The link.</returns>
 609:         private Control CreatePasswordRecoveryLink(
 610:             bool hasPasswordRecoveryIconUrl, bool hasPasswordRecoveryText) {
 611:             var listItem = new HtmlGenericControl("LI") {
 612:                 EnableViewState = false
 613:             };
 614:  
 615:             var link = new HyperLink() {
 616:                 EnableViewState = false,
 617:                 NavigateUrl = login.PasswordRecoveryUrl
 618:             };
 619:             link.MergeStyle(login.HyperLinkStyle);
 620:             listItem.Controls.Add(link);
 621:  
 622:             if (hasPasswordRecoveryIconUrl) {
 623:                 var image = new Image() {
 624:                     EnableViewState = false,
 625:                     ImageUrl = login.PasswordRecoveryIconUrl
 626:                 };
 627:                 link.Controls.Add(image);
 628:             }
 629:             if (hasPasswordRecoveryText) {
 630:                 var text = new Literal() {
 631:                     Text = login.PasswordRecoveryText
 632:                 };
 633:                 link.Controls.Add(text);
 634:             }
 635:  
 636:             return listItem;
 637:         }
 638:  
 639:         /// <summary>
 640:         /// Creates the controls that are used to render the title of the
 641:         /// <see cref="Login"/> control.
 642:         /// </summary>
 643:         /// <param name="container">
 644:         /// The parent container <see cref="Control"/> that the new control
 645:         /// is to be added to.
 646:         /// </param>
 647:         private void CreateTitleControl(Control container) {
 648:             var title = new HtmlGenericControl("H1") {
 649:                 EnableViewState = false,
 650:                 InnerText = login.TitleText
 651:             };
 652:             SetCssStyles(title, login.TitleTextStyle);
 653:             container.Controls.Add(title);
 654:         }
 655:  
 656:         /// <summary>
 657:         /// Creates the controls that are used to render the user information
 658:         /// field set for the <see cref="Login"/> control.
 659:         /// </summary>
 660:         /// <param name="container">
 661:         /// The parent container <see cref="Control"/> that the new control
 662:         /// is to be added to.
 663:         /// </param>
 664:         private void CreateUserInformationFieldSet(Control container) {
 665:             var userInformationFieldSet =
 666:                 new HtmlGenericControl("FIELDSET") {
 667:                     EnableViewState = false,
 668:                     ID = "UserInformationFieldSet"
 669:                 };
 670:             container.Controls.Add(userInformationFieldSet);
 671:  
 672:             var userInformationLegend =
 673:                 new HtmlGenericControl("LEGEND") {
 674:                     EnableViewState = false,
 675:                     InnerText = "User account information"
 676:                 };
 677:             userInformationFieldSet.Controls.Add(userInformationLegend);
 678:  
 679:             CreateUserNameControls(userInformationFieldSet);
 680:             CreatePasswordControls(userInformationFieldSet);
 681:         }
 682:  
 683:         /// <summary>
 684:         /// Creates the controls used to capture the user's account name.
 685:         /// </summary>
 686:         /// <param name="container">
 687:         /// The container <see cref="Control"/> that the user name controls
 688:         /// will be added to.
 689:         /// </param>
 690:         private void CreateUserNameControls(Control container) {
 691:             var userNameLabel = new Label {
 692:                 AssociatedControlID = "UserName",
 693:                 EnableViewState = false,
 694:                 ID = "UserNameLabel",
 695:                 Text = login.UserNameLabelText
 696:             };
 697:             userNameLabel.MergeStyle(login.LabelStyle);
 698:             container.Controls.Add(userNameLabel);
 699:  
 700:             var userName = new TextBox {
 701:                 ID = "UserName"
 702:             };
 703:             userName.MergeStyle(login.TextBoxStyle);
 704:             container.Controls.Add(userName);
 705:  
 706:             var userNameValidator = new RequiredFieldValidator {
 707:                 ControlToValidate = "UserName",
 708:                 EnableViewState = false,
 709:                 ID = "UserNameRequired",
 710:                 Text = login.UserNameRequiredErrorMessage,
 711:                 ToolTip = login.UserNameRequiredErrorMessage,
 712:                 ValidationGroup = login.ID
 713:             };
 714:             userNameValidator.MergeStyle(login.ValidatorTextStyle);
 715:             container.Controls.Add(userNameValidator);
 716:         }
 717:  
 718:         /// <summary>
 719:         /// Sets the CSS class name and CSS styles for a
 720:         /// <see cref="HtmlControl"/>.
 721:         /// </summary>
 722:         /// <param name="control">
 723:         /// The <see cref="HtmlControl"/> control.
 724:         /// </param>
 725:         /// <param name="style">
 726:         /// A <see cref="Style"/> object containing the CSS settings for
 727:         /// the control.
 728:         /// </param>
 729:         private void SetCssStyles(HtmlControl control, Style style) {
 730:             if (!style.IsEmpty) {
 731:                 if (!String.IsNullOrEmpty(style.CssClass)) {
 732:                     control.Attributes.Add("class", style.CssClass);
 733:                 }
 734:  
 735:                 var styles = style.GetStyleAttributes(login.Page);
 736:                 foreach (string key in styles.Keys) {
 737:                     control.Style.Add(key, styles[key]);
 738:                 }
 739:             }
 740:         }
 741:     }
 742: }

 

Technorati Tags: ,,

LoginAdapter.cs (27.63 kb)



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Related posts

Comments

September 18. 2009 15:38

i like
|

Tiffany Necklaces

October 1. 2009 12:13

art is a lie that tells the truth ugg classic cardy. Humor has been well defined as ugg calssic thinking in fun while feeling in earnest.The decline of literature indicates the decline of a ugg sale online nation ; the two ugg bailey button keep in their ugg classic min downward tendency. http://www.olugg.com/
|

ugg boots sale

October 1. 2009 13:00

Itisbettertowaste<ahref="www.joyceb2b.com/.../a>one'syouththan to do noting <a href="www.joyceb2b.com/...hones-c-111.html">bose headphones</a> with it at all. One <a href="http://www.joyceb2b.com/">cell phones</a> thing I know. If a jewel falls into the <a href="www.joyceb2b.com/specials.html">nokia 8800 arte</a> mire, it remains as precious as before; and though dust should ascend to <a href="http://www.joyceb2b.com/">bose in-ear headphones</a> heaven, its former worthlessness will not altered.
|

nokia8800

October 1. 2009 13:43

<a href="http://www.ggaol.com/">unlock nokia mobile</a> it is better to waste one's youth than to do noting <A href="www.ggaol.com/...a-mobiles-c-4.html">nokia mobiles</A> with it at all. One <a href="http://www.ggaol.com/specials.html">nokia sirocco</a> thing I know.If a jewel falls into the <A href="www.ggaol.com/...eadphones-c-10.html">bose headphones</A> mire, it remains as precious as before; and though dust should ascend to <a href="http://www.ggaol.com/">buy cheap nokia 8800</a> heaven, its former worthlessness will not altered.

|

nokia mobiles

October 6. 2009 06:06

Fear not that the chi flat iron life shall come to an end, but rather fear that it shall never have a ghd iv dark styler beginning. ghd iv kiss styler it is while you are patiently toiling at the little tasks of ghd hair iron life that the meaning and shape of great whole ghd mk4 iron of life dawn on you. http://www.ghdhairon.com/
|

GHD Hair Iron

October 12. 2009 23:50

To most ugg boots men , the ugg bailey button experience is like the stern light of an ugg lo pro button ship which il-luminates only the uggs boots track it has passed. Too much ugg knightsbridge experience is a dangerous thing. We know nothing of what will happen in future , but by the analogy of past experience. Absence to love is what wind is to fire. It extinguishes the small; it inflames the great. http://www.hideboots.com/

|

ugg bailey button

October 14. 2009 21:42

When the fight begins within ugg bailey button himself, a man's worth something ugg lo pro button.Have no fear of perfection---you'll never reach it. uggs boots it is better to die on your feet than to live on your knees. ugg boots life is not all beer and skittles. Fear not that the life shall come to an end, but rather fear that it shall never have a ugg knightsbridge beginning. http://www.4ezlive.com/
|

UGG Boots

November 24. 2009 07:28

<a href="http://www.asicscloset.com/">mens onitsuka tiger shoes</a>
<a href="www.asicscloset.com/...0.html">Comfortable asics onitsuka tiger mexico 66 Shoes</a>
<a href="www.asicscloset.com/...-46_53.html">Sporty Men's Asics Onitsuka Tiger Midrunner Shoes</a>
<a href="www.asicscloset.com/...c-46_52.html">Cheap asics onitsuka tiger mini clubman shoes</a>
|

asics onitsuka

November 24. 2009 07:29

<a href="www.toamazingstore.com/...s-c-52.html">UGG" rel="nofollow">www.toamazingstore.com/...s-c-52.html">UGG Cardy Grey</a>
<a href="www.toamazingstore.com/...s-c-52.html">UGG" rel="nofollow">www.toamazingstore.com/...s-c-52.html">UGG Classic Cardy</a>
<a href="www.toamazingstore.com/...-c-40.html">UGGS Crochet Boots</a>
|

ugg classic

December 11. 2009 20:28

<a href="http://www.oluggs.com/">uggs on sale</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html">bailey" rel="nofollow">www.oluggs.com/...eybuttonc39.html">bailey button</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html"> cheap uggs</a>
<a href="www.oluggs.com/...ccardyc27.html">discount ugg boots</a>
<a href="www.oluggs.com/...assictallc31.html">women's ugg</a>
<a href="www.oluggs.com/uggmayfairec46.html">UGG Mayfaire</a>
<a href="www.oluggs.com/...tnutbootsp1067.html">ugg classic short chestnut</a>
<a href="www.oluggs.com/...lassicshortc30.html">ugg classic short </a>
<a href="www.oluggs.com/...bootsgreyp1113.html">ugg bailey button grey</a>
<a href="www.oluggs.com/uggsundancec35.html">ugg sundance boots</a>
<a href="www.oluggs.com/uggnightfallc34.html">ugg nightfall boots</a>
<a href="www.oluggs.com/uggultratallc38.html">ugg" rel="nofollow">www.oluggs.com/uggultratallc38.html">ugg ultra tall</a>
<a href="www.oluggs.com/uggultratallc38.html">ugg" rel="nofollow">www.oluggs.com/uggultratallc38.html">ugg ultral short</a>
<a href="www.oluggs.com/...ssiccardyc27.html">cardy boots</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg boots</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg boots sale</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg boots uk</a>
<a href="http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg" rel="nofollow">http://www.oluggs.com">ugg australia</a>
<a href="http://www.oluggs.com">cheap ugg boots</a>
<a href="www.oluggs.com/...lassiccardyc27.html">ugg cardy</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html">bailey" rel="nofollow">www.oluggs.com/...eybuttonc39.html">bailey button uggs</a>
<a href="www.oluggs.com/uggbaileybuttonc39.html">ugg bailey</a>
<a href="www.oluggs.com/uggclassictallc31.html">ugg classic tall</a>
<a href="http://www.myugleahy.com/">uggs" rel="nofollow">http://www.myugleahy.com/">uggs on sale</a>
<a href="http://www.myugleahy.com/">ugg boots on sale</a>
<a href="http://www.myugleahy.com/">discount ugg boots</a><a href="www.myugleahy.com/...sicshortc86.html">UGG" rel="nofollow">www.myugleahy.com/...sicshortc86.html">UGG Classic</a>
<a href="www.myugleahy.com/...sicshortc86.html">UGG" rel="nofollow">www.myugleahy.com/...sicshortc86.html">UGG Classic Short</a>
<a href="www.myugleahy.com/...sictallc103.html">UGG Classic Tall</a>
<a href="www.myugleahy.com/...iccardyc104.html">UGG Classic Cardy</a>
<a href="www.myugleahy.com/...sicminic102.html">UGG Classic Mini</a>
|

UGGStyle

December 14. 2009 09:24

<strong><a href="www.souggs.com/specials.html">Australia Ugg Boots</a></strong> becoming more and more popular,new style <strong><a href="http://www.souggs.com/">ugg boots</a></strong> will be the best seller for this Christmas,includes<strong><a href="www.souggs.com/products_all.html">Ugg Knightsbridge</a>,<a href="www.souggs.com/...ley-button-c-2.html">UGG Bailey Button</a></strong>;and the <strong><a href="www.shoeshotsale.com/.../strong><strong><a href="www.souggs.com/ugg-tall-5815-c-3.html">ugg classic tall boots,</a></strong> <strong><a href="www.souggs.com/...cardy-5819-c-1.html">ugg cardy boots</a></strong> also hot sale for these years,you can choose your lovely <strong><a href="www.souggs.com/products_new.html">UGGS Boots</a></strong> on shoesem.com,You can choose the <strong><a href="www.souggs.com/..._products.html">discount ugg boots</a></strong> or the newest <strong><a href="www.souggs.com/.../strong> for yourself or your friends.
|

ugg

December 14. 2009 10:17

<strong><a href="www.souggs.com/specials.html">Australia Ugg Boots</a></strong> becoming more and more popular,new style <strong><a href="http://www.souggs.com/">ugg boots</a></strong> will be the best seller for this Christmas,includes<strong><a href="www.souggs.com/products_all.html">Ugg Knightsbridge</a>,<a href="www.souggs.com/...ley-button-c-2.html">UGG Bailey Button</a></strong>;and the <strong><a href="www.shoeshotsale.com/.../strong><strong><a href="www.souggs.com/ugg-tall-5815-c-3.html">ugg classic tall boots,</a></strong> <strong><a href="www.souggs.com/...cardy-5819-c-1.html">ugg cardy boots</a></strong> also hot sale for these years,you can choose your lovely <strong><a href="www.souggs.com/products_new.html">UGGS Boots</a></strong> on shoesem.com,You can choose the <strong><a href="www.souggs.com/..._products.html">discount ugg boots</a></strong> or the newest <strong><a href="www.souggs.com/.../strong> for yourself or your friends.
|

ugg

December 17. 2009 16:06

S11217C2 Do you think I can stay timberland boots uk to become nothing to you ? Do you think I am a timberland boot automaton ? --a discount timberland boots machine without feelings ? and can bear classic timberland boots to have my morsel of bread snatched from my lips, and my drop of kids timberland boots living water dashed from my cup? Do you think, because I am timberland mens shoes poor, obscure, plain, and little, I am soulless and heartless? You think timberland 6 inch boots wrong!--I have as much timberland custom boots soul as you,--and full as much timberland roll top boots heart! And if God had timberland womens shoes gifted me with some beauty and much wealth, I should have made it as hard for you to leave me, as it is now for me to leave you. I am not talking to you now through the medium of timberland hiking boots custom, conventionalities, nor even of mortal flesh. http://www.runtimberland.com/
|

timberland boots uk

December 18. 2009 06:11

Just wanted to say thanks for this.
|

Mississippi Payday Loans

December 26. 2009 03:38

Hey mate, superb post! Pleasee continue this great work...
|

free adventure games

December 30. 2009 09:21

Considerably, the blog post is in reality the sweetest on this precious subject. I harmonize with your conclusions and will thirstily look forward to your next updates. Saying thanks will not just be adequate, for the increadible lucidity in your writing. I will instantly grab your rss feeds to stay privy of any updates. Gratifying work and much success in your business endeavors! Best regards, Jason.
|

son moda

January 21. 2010 21:35

To go forward is to move toward perfection. March on, and fear not the thorns, or the sharp stones on life's path.
|

instant loans

January 25. 2010 20:04

hey buddy, I found your weblog from google and read a few of your other articles. They are gorgeous. Pleasee keep it up!! Cheers, Malcolm.
|

cheap hosting

January 26. 2010 15:56

http://www.tiffanycome.com/ Tiffany & Co
http://www.tiffanycome.com/accessories-c-7.html Tiffany Jewellery
http://www.tiffanycome.com/bangles-c-5.html tiffany and co
http://www.tiffanycome.com/bracelets-c-2.html Tiffany Bracelet On Sale
http://www.tiffanycome.com/cufflinks-c-6.html links of london
http://www.tiffanycome.com/earrings-c-3.html tiffany co london
http://www.tiffanycome.com/necklaces-c-1.html links london
http://www.tiffanycome.com/rings-c-4.html Tiffany Rings
http://www.tiffanycome.com/watches-c-8.html tiffany and company
|

tiffany jewellery

January 27. 2010 04:31

To waken interest and kindle enthusiasm is the sure way to teach easily and successfully.
|

payday loans

January 30. 2010 14:16

Hi, I applaud your blog for informing people, very interesting article, keep up it coming Smile
|

sandals shoes

February 10. 2010 23:38

Hi, your website's theme is superb and . Your posts are cool. Please keep up the good work. Cheers!.
|

oksijen terapi

February 11. 2010 03:45

I was looking for this the other day. i dont usually post in forums but i wanted to say thank you!
|

quick payday loans

February 11. 2010 18:23

Howdy site owner, thank you for sharing this information! I found it superb. Cheers, Benjamin..
|

discount phentermine

February 25. 2010 01:38

my God, i thought you were going to chip in with some decisive insght at the end there, not leave it with ‘we leave it to you to decide’.
|

pay day loans

February 26. 2010 20:13

Hello, I found your blog in a new directory of blogs. I dont know how your blog came up, must have been a typo, Your blog looks good. Have a nice day.
|

cash advance

March 2. 2010 20:44

my God, i thought you were going to chip in with some decisive insght at the end there, not leave it with "we leave it to you to decide".
|

Herbal colon cleanse

March 4. 2010 07:41

I love streaming movies online, it is way cheaper than going to the theaters.
|

hd movies

March 4. 2010 14:31

I love streaming movies online, it is way easier than going to the theaters.
|

watch movies online

March 6. 2010 04:03

I really like the fresh perpective you did on the issue. Really was not expecting that when I started off studying. Your concepts were easy to understand that I wondered why I never looked at it before. Glad to know that there's an individual out there that definitely understands what he's discussing. Great job
|

Erik Erven

March 6. 2010 13:09

Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info i found on Login adapter: lessons learned.
|

teeth whitening products

March 8. 2010 12:49

Hey I love your style I will subscribe for your feed please keep posting!
|

Stretch marks treatment

March 9. 2010 05:33

|

live sex action

Add comment


 

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

March 11. 2010 04:57

|