7.3. Save Anonymous User Profiles
Note: You can use the Profile service to store information about anonymous users, instead of an authenticated user ID.
While ASP.NET 2.0 employs a unique user ID to associate a user with a profile, it is often desirable to associate an anonymous user with a profile as well. For example, at a typical e-commerce web site, users who have not yet been authenticated are typically encouraged to add items to their shopping carts while they browse the merchandise. Only when a user is ready to check out is she then required to log into the system and supply other information, such as credit card numbers and a shipping address.
In ASP.NET 2.0, you can keep track of anonymous users through the use of the Globally Unique Identifier (GUID).
7.3.1. How do I do that?
In this lab, you will see how you can implement anonymous personalization in ASP.NET 2.0. You will also learn how you can store complex data types into the profile property.
Using the same project created in the last lab (C:\ASPNET20\chap07-Profile), create a new Images folder in your project and add the images as shown in Figure 7-11 (you can download these images from the O'Reilly support site at http://www.oreilly.com/catalog/aspnetadn/). We'll use these images to represent items that can be ordered on our test page.
Figure 7-12. Saving the images in the Images folder
Now we need to create a test page. Add a new Web Form to the root of the project and name it Products.aspx.
Populate the Products.aspx page with the images you added to your project in Step 1, as shown in Figure 7-12.
Figure 7-13. Populating the Products.aspx page
Now add two "Add to cart" buttons to the page so users can drop the two items into a shopping cart, regardless of whether they've been authenticated. The best place to save shopping cart items is the Profile object.
Add a new class to the project and name it ShoppingCart.vb. You will be prompted to save the file in the App_Code folder. Click Yes. This new class will implement the shopping cart used in this application.
Code the ShoppingCart.vb class as shown in Example 7-1. The Cart class allows items to be added to an ArrayList object.
Example 7-1. ShoppingCart.vb
Imports Microsoft.VisualBasic Imports System.Xml.Serialization Namespace OReilly Public Structure itemType Dim isbn As String Dim qty As Integer End Structure <XmlInclude(GetType(itemType))> _ Public Class Cart '---use public for Xml serialization--- Public items As New ArrayList Public Sub AddItem(ByVal isbn As String, ByVal qty As Integer) Dim cartItem As New itemType cartItem.isbn = isbn cartItem.qty = qty items.Add(cartItem) End Sub End Class End Namespace
To allow anonymous identification, add the following code to the Web.config file for your application (shown in Figure 7-13). In particular, you need to specify the <anonymousIdentification> element:
Figure 7-14. Modifying the Web.config file in the root of the application
Note: You need to specify the XmlInclude attribute to allow the XmlSerializer to recognize a type when it serializes or deserializes the itemType data type.
<system.web> <anonymousIdentification enabled="true"/> <profile> <properties> <add name="FirstName" type="System.String"/> <add name="LastName" type="System.String"/> <add name="shoppingcart" allowAnonymous="true" type="OReilly.Cart" serializeAs="Xml"/> </properties> </profile> ...
Note: Note that you have to explicitly identify the individual profile property to allow for anonymous access via the allowAnonymous attribute.
You define the type for the shoppingcart profile property as OReilly.Cart. This type refers to the Cart class that you have defined in ShoppingCart.vb. The profile property shoppingcart will be serialized as an XML string so that it can be stored in a database.
Switch to the code-behind of Products.aspx and add the code for the btnAddToCart_Click( ) method shown in this step. This method will retrieve the shopping cart associated with the current user (authenticated or anonymous) and then add the item selected. The new shopping cart is then saved back into the Profile object:
Protected Sub btnAddToCart_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles btnAddtoCart1.Click, _ btnAddtoCart2.Click Dim myCart As OReilly.Cart '---retrieve the existing cart myCart = Profile.shoppingcart If myCart Is Nothing Then myCart = New OReilly.Cart End If Dim isbn As String Select Case CType(sender, Button).ID Case "btnAddtoCart1" : isbn = "0-596-00536-9" Case "btnAddtoCart2" : isbn = "0-596-00757-4" End Select myCart.AddItem(isbn, 1) '---save the cart back into the profile Profile.shoppingcart = myCart End Sub
Code the Page_Load event so that when the page is loaded, you can use the Membership class to check whether the user is authenticated and print out the related information about the user:
Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles Me.Load Dim user As MembershipUser = Membership.GetUser If user Is Nothing Then Response.Write("You have not logged in yet.") End If End Sub
To test the application, press F5. In Products.aspx, you should see the message "You have not logged in yet" (see Figure 7-14).
Figure 7-15. Viewing the Products.aspx page
Click on the two "Add to cart" buttons, and the two items are added to the Profile object. To view the information saved by the Profile object, use Server Explorer to view the content of the aspnet_Profile table in the ASPNETDB.MDF file. Notice that the shoppingcart profile property is saved as an XML string PropertyValuesString field:
<?xml version="1.0" encoding="utf-16"?> <Cart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/ 2001/XMLSchema"> <items> <anyType xsi:type="itemType"> <isbn>0-596-00536-9</isbn> <qty>1</qty> </anyType> <anyType xsi:type="itemType"> <isbn>0-596-00757-4</isbn> <qty>1</qty> </anyType> </items> </Cart>
Also, if you examine the aspnet_Users table, you will notice that a new user has been created. This user account is created to identify the anonymous user.
Anonymous ID and GUID
If anonymous identification is enabled, when an unauthenticated user tries to save information into the Profile object, an anonymous user ID is generated for the user. This ID is a GUID (Globally Unique Identifier) that is guaranteed to be unique for each user.
You can programmatically retrieve the anonymous ID for the user via Request.AnonymousId.
7.3.2. What about...
To use binary serialization instead of XML serialization, you need to explicitly mark your object to be persisted as serializable by using the Serializable( ) attribute:
Imports Microsoft.VisualBasic Imports System.Xml.Serialization <Serializable( )> _ Public Structure itemType Dim isbn As String Dim qty As Integer End Structure Namespace OReilly <Serializable( ), _ XmlInclude(GetType(itemType))> _ Public Class Cart '---use public for Xml serialization--- Public items As New ArrayList Public Sub AddItem(ByVal isbn As String, ByVal qty As Integer) Dim cartItem As New itemType cartItem.isbn = isbn cartItem.qty = qty items.Add(cartItem) End Sub End Class End Namespace
The object that is persisted will then be saved in the PropertyValuesBinary field instead of the PropertValuesString field in the aspnet_Profile table.
7.3.3. Where can I learn more?
Notice that in the Cart class, I have used the Public access modifier for the items array. This is because only member variables that are defined as public can be persisted in XML serialization. If you choose to use binary serialization instead, you can define items as private. For more information on Binary and XML Serialization, refer to my two articles at ONDotNet.com: