WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Personalization in ASP.NET 2.0
Pages: 1, 2

Saving Complex Types

There are times when you'll want to save more than just strings or integers to the Profile. It is convenient to be able to save collections or user-defined types. To demonstrate how to add more complex items to the Profile, you'll allow the user to select a series of book titles to store (as if added to a shopping cart). To begin, open the ASP.NET Web Site Administration Tool. In Visual Studio, click on WebSite -> ASP.NET Configuration, as shown in Figure 6.

Figure 6

Figure 6. ASP.NET configuration

When the Web Site Administrator opens, click on the Profile tab, and then click on Create Profile Properties, as shown in Figure 7.

Figure 7

Figure 7. Site administration

On the Profiles Property page, set the property name, be sure to check the "Make this property available for anonymous users" check box, and fill in the fully qualified type name, in this case: System.Collections.Specialized.StringCollection (these areas are highlighted in Figure 8). Click Save and OK to save your profile data.

Figure 8

Figure 8. Setting properties

To see this collection at work, you'll add a CheckBoxList to the ProfileInfo page, which you will populate with the name of four books. Hand-populate this list by clicking on the Items property, and filling in the ListItems Collection Editor, as shown in Figure 9.

Figure 9

Figure 9. Adding personalization values

When the user's profile is updated, the user may select one or more books. When the Save button is clicked, the click handler will call the private helper method AddBooks:


private void AddBooks()
{
  Profile.ChosenBooks = new System.Collections.Specialized.StringCollection();
  foreach (ListItem item in this.cblBooks.Items)
  {
    if (item.Selected)
    {
      Profile.ChosenBooks.Add(item.Value.ToString());
    }
  }
}

Each time you save the books you create an instance of the String collection, and you then iterate through the checked list boxes, looking for the selected items. Each selected item is added to the string collection within the profile (the ChosenBooks property).

To confirm that this data has been stored, you'll add a list box to the Default.aspx page, and you'll bind that list box to the collection in the profile:


if (Profile.ChosenBooks != null)
{
  this.lbBooks.DataSource = Profile.ChosenBooks;
  this.lbBooks.DataBind();
  this.lbBooks.Visible = true;
}

To make your code a bit easier to maintain, you want to have the selected values (name, phone, selected books, etc.) pre-filled when you return to the profile editing page, so you'll implement a bit of code on Page_Load to get the initial values from the Profile object:

 
public void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack && Profile.UserName != null)
  {
    this.lastName.Text = Profile.lastName;
    this.firstName.Text = Profile.firstName;
    this.phone.Text = Profile.phoneNumber;
    this.birthDate.Text = Profile.birthDate.ToShortDateString();
    if (Profile.ChosenBooks != null)
    {
      foreach (ListItem li in this.cblBooks.Items)
      {
        foreach (string s in Profile.ChosenBooks)
        {
          if (li.Text == s)
          {
            li.Selected = true;
          } // end if thext is the same
        } // end foreach string in saved isbns
      } // end foreach item in the list box
    } // end if savedisbns not null
  } // end if not postback
} // end Page_Load

Each time you navigate to this page, the values are updated from the profile, and you are free to change them, as shown in Figure 10.

Figure 10

Figure 10

When you click Save, the values are stored in the Profile object, and displayed in the default page, as shown in Figure 11.

Figure 11

Figure 11

Anonymous Personalization

It is possible that you'll want to allow your user to fill up a shopping cart (or otherwise create data to store in a Profile) before logging in. To allow for this, you may enable anonymous personalization. Return to Web.config, and mark a few of the properties allowAnonymous="true". Also add an element enabling anonymousIdentification, as shown highlighted in Figure 12.

Figure 12

Figure 12. Web.config

Redesign your Default.aspx page so that the hyperlink that links to the profile information page, and the lbBooks list box, are both outside of the LoginView control (so that you can see the hyperlink and the list, even if you are not logged in). While you are at it, rename Add Profile Info to Profile Info, since you will be using this link to add, and edit, the profile info.

When an anonymous user chooses books, the user will be automatically be assigned a Globally Unique Identifier (GUID), and an entry will be made in the database for that ID. However, note that only those properties marked with allowAnonymous may be stored, so you must modify your save_Click event handler in ProfileInfo.aspx.cs accordingly.

void save_Click(object sender, EventArgs e)
{
  if (Profile.IsAnonymous == false)
  {
    Profile.lastName = this.lastName.Text;
    Profile.firstName = this.firstName.Text;
    Profile.phoneNumber = this.phone.Text;
    Profile.birthDate = Convert.ToDateTime(this.birthDate.Text);
  }
  AddBooks();
  Response.Redirect("Default.aspx");
}

When saving your Profile data, you check whether the IsAnonymous property is false. If it is false, then you have a logged-in user, and you may get all of the properties; otherwise, you may get only those that are allowed for anonymous users. Similarly, so as not to display default (and possibly bizarre) data, you will want to check the IsAnonymous flag when you pre-fill the fields on page load:

public void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack && Profile.UserName != null )
  {
    if (Profile.IsAnonymous == false)
    {
      this.lastName.Text = Profile.lastName;
      this.firstName.Text = Profile.firstName;
      this.phone.Text = Profile.phoneNumber;
      this.birthDate.Text = Profile.birthDate.ToShortDateString();
    }
  
    if (Profile.ChosenBooks != null)
      {
        foreach (ListItem li in this.cblBooks.Items)
        {
          foreach (string s in Profile.ChosenBooks)
          {
            if (li.Text == s)
            {
              li.Selected = true;
            } // end if thext is the same
          } // end foreach string in saved isbns
        } // end foreach item in the list box
      } // end if savedisbns not null
  } // end if not postback
} // end Page_Load

 

Notice that if IsAnonymous is true, only the book list will be initialized from the Profile.

Run the application, do not log in, but do click the Profile Info link. Select a few books and click Save. When you return to the default page, you are still not logged in, but your selected books are displayed, as shown in Figure 13.

Figure 13

Figure 13: Using personalization

A quick look at the database shows that an ID has been created for this anonymous user (and the UserName has been set to the GUID generated). In addition, the shopping cart has been stored in the corresponding record, as shown in Figure 14.

Figure 14

Figure 14. The data

Notice in Figure 14 that the UserName is the GUID, that the IsAnonymous checkbox is checked, and that in the Profile, this user has a record of which books where chosen.

Migrating from Anonymous to Authenticated

A typical scenario in an online store is that your anonymous user will, eventually, be identified (perhaps at checkout). It is important that you be able to migrate the Profile data you've accumulated for the anonymous user to the appropriate authenticated user so that, for example, the shopping cart items are not lost. You do this by writing a global handler in global.asax.

If your project does not yet have a global.asax file, right-click on the project and choose Add New Item. One of your choices will be Global Application Class, and it will automatically be named global.asax. Within that class, add a method to handle the MigrateAnonymous event that is fired when a user logs in:

void Profile_MigrateAnonymous(object sender, ProfileMigrateEventArgs e)
{
  ASP.HttpProfile anonymousProfile = Profile.GetProfile(e.AnonymousId);
  if (anonymousProfile != null && anonymousProfile.ChosenBooks != null)
  {
    foreach (string s in anonymousProfile.ChosenBooks)
    {
      Profile.ChosenBooks.Remove(s);  // avoid duplicates
      Profile.ChosenBooks.Add(s);
    }
  }
}

The first step is to get a reference to the profile that matches the AnonymousID that is passed in as a property of the ProfileMigrateEventArgs structure. If the reference is not null, then you know that there is a matching anonymous profile, and that you may pick up whatever data you need from that profile. In this case, we copy over the ChosenBooks collection.

The user's profile is updated, and the books chosen as an anonymous user are now part of that user's profile.

Jesse Liberty is a senior program manager for Microsoft Silverlight where he is responsible for the creation of tutorials, videos and other content to facilitate the learning and use of Silverlight. Jesse is well known in the industry in part because of his many bestselling books, including O'Reilly Media's Programming .NET 3.5, Programming C# 3.0, Learning ASP.NET with AJAX and the soon to be published Programming Silverlight.


Read more Liberty on Whidbey columns.

Return to ONDotnet.com.