Add Profile Items in CreateUserWizard and Recursive FindControl

Date Published: 24 August 2006

Add Profile Items in CreateUserWizard and Recursive FindControl

There's an example in Professional ASP.NET 2.0 that shows how to add a few profile items to a CreateUserWizard. Unfortunately, it doesn't work in certain cases, specifically when the profile item in question is set to allowAnonymous="false". When that happens, you will receive this error:

"This property cannot be set for anonymous users."

One fix is to simply set the allowAnonymous flag to true, but if it's not something you want anonymous users to be able to set, that's not ideal. Another thing that can be tricky is referencing your Textbox (or other web form) controls within the CreateUserWizard. I'll cover that next.

For the profile issue, the fix is to create a local instance of ProfileCommon, as described in this thread on Updating Profile of Created User.

Walter Wang [MSFT] Writes:

I think you can create and save the profile manually after you created the
user:

ProfileCommon p = (ProfileCommon) ProfileCommon.Create(username, true);
p.UserInfo.UserEmail = UserName.Text;

One thing he leaves out in the … is this line, which is needed to actually save the profile data:

p.Save();

That works, but what about if your profile item's textbox is inside the CreateUserWizard control? In that case, you need to get a reference to the textbox (let's call it FullNameTextBox). One option to do this is to use some code like this:

// get an instance of the FullName textbox from the wizard's controls hierarchy.

TextBox FullNameTextBox = CreateUserWizard1.WizardSteps\[0].Controls\[0].Controls\[0].Controls\[0].Controls\[0].FindControl("FullName")asTextBox;

if(FullNameTextBox!=null)

{

Profile.FullName = FullNameTextBox.Text;

}

Unfortunately this is some very hard to read, and hard to maintain, code. It's very brittle. Wouldn't it be nice if FindControl() actually recursed through the Controls() collection of each control in a hierarchy? Well, it just so happens that my buddyAmbrose Little has some code that will do just this, which he was nice enough to share with me (and which I'm sharing with you). Replace the above ugliness with this code (which also includes the ProfileCommon fix):

protected void CreateUserWizard1_CreatedUser(object sender,EventArgs e)
{
  // get an instance of the FullName textbox from the wizard's controls hierarchy.
  TextBox FullNameTextBox =FindControl(CreateUserWizard1,"FullName") as TextBox;

  if(FullNameTextBox != null)
  {
    ProfileCommonp = (ProfileCommon)ProfileCommon.Create(((CreateUserWizard)sender).UserName,true);
    p.FullName = FullNameTextBox.Text;

    p.Save();
  }
}

You can see that I'm now using the FindControl() method, which is defined at Page level (put it in your BasePage class, or call it statically from some Common class, which is what I'm actually doing). Here is the code:

///<summary>
///Returns a control if one by that name exists in the hierarchy of the controls collection of the start control
///</summary>
///<param name="start"></param>
///<param name="id"></param>
///<returns></returns>
System.Web.UI.ControlFindControl(System.Web.UI.Control start,string id)
{
  System.Web.UI.Control foundControl;
  if(start !=null)
  {
    foundControl = start.FindControl(id);
    if(foundControl !=null)
      return foundControl;
    foreach(Control c in start.Controls)
    {
      foundControl = FindControl(c, id);
      if(foundControl !=null)
        return foundControl;
    }
  }
  return null;
}
Steve Smith

About Ardalis

Software Architect

Steve is an experienced software architect and trainer, focusing on code quality and Domain-Driven Design with .NET.