thedude112286
asked on
Dynamic controls
I am developing a dynamic web control. Right now, I'm just trying to get a (I thought) simple control to request a password, fire an event if it's correct, and write a failure message if it's wrong. It works fine if I enter the right password, but if I enter the wrong password, my failure message never shows up.
Basically, I set the viewstate to indicate whether or not to show the failure message, create all controls in an overrided CreateChildControls, and call EnsureChildControls whenever I want them to show up. What am I doing wrong?
Here is the code:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
/// <summary>
/// Handles admin password request and authentication.
/// </summary>
public class AdminPasswordControl : WebControl {
readonly string pwdTB_ID = "AdminPwdTB";
readonly string pwdButton_ID = "AdminPwd";
readonly string thisState = "AdminPasswordRequestContr olState";
enum States {
Clear, Failed
}
public event EventHandler PasswordAccepted;
public AdminPasswordControl() {
this.EnableViewState = true;
ViewState.Add(thisState, States.Clear);
Config.Instance.Sha1jsUrl = "sha1.js";
System.Security.Cryptograp hy.SHA1 sha1 = new System.Security.Cryptograp hy.SHA1Cry ptoService Provider() ;
byte[] hash = sha1.ComputeHash(System.Te xt.Encodin g.UTF8.Get Bytes("pwd "));
Config.Instance.AdminPassw ord = Convert.ToBase64String(has h).Replace ("=", String.Empty);
EnsureChildControls();
}
public void OnSubmit(object sender, EventArgs e) {
Button btn = (Button)sender;
string sha1EnteredPwd = ((TextBox)this.FindControl (pwdTB_ID) ).Text;
if ( Config.Instance.AdminPassw ord == sha1EnteredPwd ) {
if ( PasswordAccepted != null ) {
PasswordAccepted(this, new EventArgs());
}
}
else {
ViewState[thisState] = States.Failed;
EnsureChildControls();
}
}
protected override void CreateChildControls() {
this.Controls.Clear();
this.Controls.Add(new JavascriptIncludeControl(C onfig.Inst ance.Sha1j sUrl));
this.Controls.Add(ControlP rovider.Ge tRegularLa bel("Enter administrator password: "));
TextBox pwdTb = new TextBox();
pwdTb.ID = pwdTB_ID;
pwdTb.TextMode = TextBoxMode.Password;
pwdTb.Width = ControlProvider.InputContr olSize;
this.Controls.Add(pwdTb);
this.Controls.Add(new LineBreakControl());
Button submitBtn = ControlProvider.GetUpdateB utton(pwdB utton_ID,
new EventHandler(OnSubmit));
submitBtn.Text = "Submit";
// Hash the password before sending
submitBtn.Attributes.Add(" onClick", pwdTb.ClientID + ".value = " +
"b64_sha1(" + pwdTb.ClientID + ".value);");
this.Controls.Add(submitBt n);
if ( (States)ViewState[thisStat e] == States.Failed ) {
Label failLabel = ControlProvider.GetRegular Label("Inv alid password!");
failLabel.ForeColor = System.Drawing.Color.Red;
this.Controls.Add(failLabe l);
}
}
}
Basically, I set the viewstate to indicate whether or not to show the failure message, create all controls in an overrided CreateChildControls, and call EnsureChildControls whenever I want them to show up. What am I doing wrong?
Here is the code:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
/// <summary>
/// Handles admin password request and authentication.
/// </summary>
public class AdminPasswordControl : WebControl {
readonly string pwdTB_ID = "AdminPwdTB";
readonly string pwdButton_ID = "AdminPwd";
readonly string thisState = "AdminPasswordRequestContr
enum States {
Clear, Failed
}
public event EventHandler PasswordAccepted;
public AdminPasswordControl() {
this.EnableViewState = true;
ViewState.Add(thisState, States.Clear);
Config.Instance.Sha1jsUrl = "sha1.js";
System.Security.Cryptograp
byte[] hash = sha1.ComputeHash(System.Te
Config.Instance.AdminPassw
EnsureChildControls();
}
public void OnSubmit(object sender, EventArgs e) {
Button btn = (Button)sender;
string sha1EnteredPwd = ((TextBox)this.FindControl
if ( Config.Instance.AdminPassw
if ( PasswordAccepted != null ) {
PasswordAccepted(this, new EventArgs());
}
}
else {
ViewState[thisState] = States.Failed;
EnsureChildControls();
}
}
protected override void CreateChildControls() {
this.Controls.Clear();
this.Controls.Add(new JavascriptIncludeControl(C
this.Controls.Add(ControlP
TextBox pwdTb = new TextBox();
pwdTb.ID = pwdTB_ID;
pwdTb.TextMode = TextBoxMode.Password;
pwdTb.Width = ControlProvider.InputContr
this.Controls.Add(pwdTb);
this.Controls.Add(new LineBreakControl());
Button submitBtn = ControlProvider.GetUpdateB
new EventHandler(OnSubmit));
submitBtn.Text = "Submit";
// Hash the password before sending
submitBtn.Attributes.Add("
"b64_sha1(" + pwdTb.ClientID + ".value);");
this.Controls.Add(submitBt
if ( (States)ViewState[thisStat
Label failLabel = ControlProvider.GetRegular
failLabel.ForeColor = System.Drawing.Color.Red;
this.Controls.Add(failLabe
}
}
}
what is the value of ViewState[thisState], looks like it doesn't get equal
or what's ControlProvider.GetRegular Label, what if you try like this..?
if ((States)ViewState[thisSta te] == States.Failed) {
Label failLabel = new Label();
failLabel.Text="Invalid Password!";
failLabel.ForeColor = System.Drawing.Color.Red;
this.Controls.Add(failLabe l);
}
or what's ControlProvider.GetRegular
if ((States)ViewState[thisSta
Label failLabel = new Label();
failLabel.Text="Invalid Password!";
failLabel.ForeColor = System.Drawing.Color.Red;
this.Controls.Add(failLabe
}
where is this come from...? I mean value of thisState variable, have you checked if it's right...?
ViewState[thisState]
ViewState[thisState]
ASKER
ControlProvider.GetRegular Label just returns a label whose appearance (width, height, etc) is already set. This cut down on a lot of redundant code. I'm pretty sure that the ViewState does get set to States.Failed, but I'll double check this tonight. Is there anything wrong with the pattern used? That is, when I want to update the interface, should I just set the viewstate and then call EnsureChildControls or is there a better way to do this?
ASKER
laotzi, I call EnsureChildControls from OnSubmit so I just assumed that CreateChildControls would be called then. If it's being called before, is there any way that I can have it called after OnSubmit? Should I just add on the Login Failed label in the OnSubmit routine?
ASKER
laotzi, I have also tried calling Controls.Clear before EnsureChildControls from OnSubmit and when I do that, I end up with a blank page. This makes me think you are right about the order of execution. How can I fix this???
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
also remember that EnsureChildControls should be called after all controls are initialized on the form
ASKER
Thanks laotzi. I'll try that out.
davidlars99: If I initialize all of the controls before I call EnsureChildControls, what should CreatChildControls do? Is it even needed?
davidlars99: If I initialize all of the controls before I call EnsureChildControls, what should CreatChildControls do? Is it even needed?
Have you checked that?