Listing 15-11: Setting an anonymous cookie in the HTTP headerHTTP/1.1 200 OK Server: ASP.NET Development Server/8.0.0.0 Date: Sat, 11 Feb 2008 19:23:37 GMT X-AspNet-Version: 2.0.50727 Se
Trang 1Listing 15-11: Setting an anonymous cookie in the HTTP header
HTTP/1.1 200 OK
Server: ASP.NET Development Server/8.0.0.0
Date: Sat, 11 Feb 2008 19:23:37 GMT
X-AspNet-Version: 2.0.50727
Set-Cookie: ASPXANONYMOUS=UH5CftJlxgEkAAAAZTJkN2I3YjUtZDhkOS00NDE2LWFlYjEtOTVj
MjVmMzMxZWRmHoBU
As9A055rziDrMQ1Hu_fC_hM1; expires=Sat, 22-Apr-2008 06:03:36 GMT; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 1419
Connection: Close
From this HTTP header, you can see that a cookie —.ASPXANONYMOUS— is set to a hashed value for later retrieval by the ASP.NET personalization system
Changing the Name of the Cookie for Anonymous Identification
Cookies are used by default under the cookie name.ASPXANONYMOUS You can change the name of this
cookie from the<anonymousIdentification>element in theweb.configfile by using thecookieName
attribute, as shown in Listing 15-12
Listing 15-12: Changing the name of the cookie
<configuration>
<system.web>
<anonymousIdentification
enabled="true"
cookieName=".ASPXEvjenWebApplication" />
</system.web>
</configuration>
Changing the Length of Time the Cookie Is Stored
Also, by default, the cookie stored on the end user’s machine is stored for 100,000 minutes (which is
almost 70 days) If you want to change this value, you do it within this<anonymousIdentification>
element using thecookieTimeoutattribute, as shown in Listing 15-13
Listing 15-13: Changing the length of time the cookie is stored
<configuration>
<system.web>
<anonymousIdentification
enabled="true"
cookieTimeout="1440" />
</system.web>
</configuration>
Trang 2In this case, thecookieTimeoutvalue was changed to1440— meaning 1,440 minutes (or one day) This
would be ideal for something like a shopping cart where you do not want to persist the identification of
the end user too long
Changing How the Identifiers Are Stored
Although anonymous identifiers are stored through the use of cookies, you can also easily change this
Cookies are, by far, the preferred way to achieve identification, but you can also do it without the use of
cookies Other options include using the URI or device profiles Listing 15-14 shows an example of using
the URI to place the identifiers
Listing 15-14: Specifying how cookies are stored
<configuration>
<system.web>
<anonymousIdentification
enabled="true"
cookieless="UseUri" />
</system.web>
</configuration>
BesidesUseUri, other options includeUseCookies,AutoDetect, andUseDeviceProfile The following
list reviews each of the options:
❑ UseCookies: This is the default setting If you set no value, ASP.NET assumes this is the value
UseCookiesmeans that a cookie is placed on the end user’s machine for identification
❑ UseUri: This value means that a cookie will not be stored on the end user’s machine, but instead
the unique identifier will be munged within the URL of the page This is the same approach used
for cookieless sessions in ASP.NET 1.0/1.1 Although this is great if developers want to avoid
sticking a cookie on an end user’s machine, it does create strange looking URLs and can be an
issue when an end user bookmarks pages for later retrieval
❑ AutoDetect: Using this value means that you are letting the ASP.NET engine decide whether
to use cookies or use the URL approach for the anonymous identification This is done on a
per-user basis and performs a little worse than the other two options ASP.NET must check the
end user before deciding which approach to use My suggestion is to useAutoDetectinstead
ofUseUriif you absolutely must allow for end users who have cookies turned off (which is rare
these days)
❑ UseDeviceProfile: Configures the identifier for the device or browser that is making the
request
Looking at the Anonymous Identifiers Stored
In order to make the anonymous identifiers unique, a globally unique GUID is used You can also now
grab hold of this unique identifier for your own use In order to retrieve the GUID, theRequestobject
has been enhanced with anAnonymousIDproperty TheAnonymousIDproperty returns a value of type
Trang 3String, which can be used in your code as shown here:
Label1.Text = Request.AnonymousID
Working with Anonymous Identification
In working with the creation of anonymous users, be aware of an important event which you can use
form yourGlobal.asaxfile that can be used for managing the process:
By using theAnonymousIdentification_Creatingevent, you can work with the identification of the end user as it occurs For instance, if you do not want to use GUIDs for uniquely identifying the end user, you can change the identifying value from this event instead
To do so, create the event using the event delegate of typeAnonymousIdentificationEventArgs, as
illustrated in Listing 15-15
Listing 15-15: Changing the unique identifier of the anonymous user
VB
Public Sub AnonymousIdentification_Creating(ByVal sender As Object, _
ByVal e As AnonymousIDentificationEventArgs)
e.AnonymousID = "Bubbles " & DateTime.Now() End Sub
C#
public void AnonymousIdentification_Creating(object sender,
AnonymousIDentificationEventArgs e)
{
e.AnonymousID = "Bubbles " + DateTime.Now;
}
TheAnonymousIdentificationEventArgsevent delegate exposes anAnonymousIDproperty that assigns the value used to uniquely identify the anonymous user Now, instead of a GUID to uniquely identify
the anonymous user as
d13fafec-244a-4d21-9137-b213236ebedb
theAnonymousIDproperty is changed within theAnonymousIdentification_Creatingevent to
Bubbles 2/10/2008 2:07:33 PM
Anonymous Options for Personalization Properties
If you have tried to get the anonymous capability working, you might have gotten the error shown in
Figure 15-4
Trang 4Figure 15-4
To get your application to work with anonymous users, you have to specify which personalization
prop-erties you wish to enable for the anonymous users visiting your pages This is also done through the
web.configfile by adding theallowAnonymousattribute to the<add>element of the properties you
have defined within the<properties>section (see Listing 15-16)
Listing 15-16: Turning on anonymous capabilities personalization properties
<properties>
<add name="FirstName" type="System.String" />
<add name="LastName" type="System.String" />
<add name="LastVisited" type="System.DateTime" allowAnonymous="true" />
<add name="Age" type="System.Integer" />
<add name="Member" type="System.Boolean" />
</properties>
In this example, theLastVisitedproperty is set to allow anonymous users by setting the
allowAnony-mousattribute totrue Because this is the only property that works with anonymous users, the rest of the
defined properties do not store information for these types of users
Warnings about Anonymous User Profile Storage
Taking into account everything said so far about anonymous users, you should be very careful about how
you approach this option Storing profile information about anonymous users can dramatically populate
the data store you are using For instance, in my examples, I am using Microsoft’s SQL Server Express
Edition, and I stored profile information for one authenticated user and then for a single anonymous
user This puts information for both these users in the aspnet_Profile and the aspnet_Users table
The two users listed in the aspnet_Users table are shown in Figure 15-5
In this figure, the anonymous user is highlighted with the gray bar, and you can see that this user has
a pretty cryptic name, which is theRequest.AnonymousIDpresented earlier The other big difference
between the two users is shown with theIsAnonymouscolumn in the table The anonymous user has a
setting oftruefor this column while the authenticated user has a setting offalse Because your database
Trang 5Figure 15-5
can fill up quickly with anonymous user information, you should weigh which information you really
need to store on these types of users
Programmatic Access to Personalization
When an ASP.NET page is invoked, ASP.NET creates a class (ProfileCommon) by inheriting from
theProfileBaseclass, which it uses to strongly type the profile properties that were defined
in theweb.configfile This created class, meant to deal with the user’s profile store, gets and sets
profile properties through the use of theGetPropertyValueandSetPropertyValuemethods from the
ProfileBaseclass
As you would expect, ASP.NET provides you with the hooks necessary to get at specificProfileevents using theProfileModuleclass TheProfileModuleclass is what ASP.NET itself uses to create and store profile information in the page’sProfileobject
TheProfileModuleclass exposes three events that you can use to handle your user’s profile situations These events,MigrateAnonymous,Personalize, andProfileAutoSaving, are focused around the area
of authentication Because this section just showed you how to work with anonymous users in your
applications, this section now looks at how to migrate these users from anonymous users to authenticated users — because you are most likely going to want to move their profile properties as well as change
their status
Migrating Anonymous Users
When working with anonymous users, you must be able to migrate anonymous users to registered users For example, after an end user fills a shopping cart, he can register on the site to purchase the items At that moment, the end user switches from being an anonymous user to a registered user
For this reason, ASP.NET provides aProfile_MigrateAnonymousevent handler enabling you to migrate anonymous users to registered users TheProfile_MigrateAnonymousevent requires a data class of
Trang 6typeProfileMigrateEventArgs It is placed either in the page that deals with the migration or within
theGlobal.asaxfile (if it can be used from anywhere within the application) The use of this event is
illustrated in Listing 15-17
Listing 15-17: Migrating anonymous users for particular personalization properties
VB
Public Sub Profile_MigrateAnonymous(ByVal sender As Object, _
ByVal e As ProfileMigrateEventArgs)
Dim anonymousProfile As ProfileCommon = Profile.GetProfile(e.AnonymousID)
Profile.LastVisited = anonymousProfile.LastVisited
End Sub
C#
public void Profile_MigrateAnonymous(object sender,
ProfileMigrateEventArgs e)
{
ProfileCommon anonymousProfile = Profile.GetProfile(e.AnonymousID);
Profile.LastVisited = anonymousProfile.LastVisited
}
From this example, you create an instance of theProfileCommonobject and populate it with the
profile from the visiting anonymous user Then from there, you can use the instance to get at all
the profile properties of that anonymous user That means that you can then populate a profile through
a movement from the anonymous user’s profile information to the authenticated user’s profile system
Listing 15-17 shows how to migrate a single personalization property from an anonymous user to the
new registered user In addition to migrating single properties, you can also migrate properties that
come from personalization groups This is shown in Listing 15-18
Listing 15-18: Migrating anonymous users for items in personalization groups
VB
Public Sub Profile_MigrateAnonymous(ByVal sender As Object, _
ByVal e As ProfileMigrateEventArgs)
Dim au As ProfileCommon = Profile.GetProfile(e.AnonymousID)
If au.MemberDetails.DateJoined <> "" Then
Profile.MemberDetails.DateJoined = DateTime.Now().ToString() Profile.FamilyDetails.MarriedStatus = au.FamilyDetails.MarriedStatus End If
AnonymousIdentificationModule.ClearAnonymousIdentifier()
End Sub
C#
public void Profile_MigrateAnonymous(object sender,
ProfileMigrateEventArgs e)
{
Trang 7ProfileCommon au = Profile.GetProfile(e.AnonymousID);
if (au.MemberDetails.DateJoined != String.Empty) { Profile.MemberDetails.DateJoined = DateTime.Now.ToString();
Profile.FamilyDetails.MarriedStatus = au.FamilyDetails.MarriedStatus;
} AnonymousIdentificationModule.ClearAnonymousIdentifier();
}
Using this event in theGlobal.asaxfile enables you to logically migrate anonymous users as they
register themselves with your applications The migration process also allows you to pick and choose
which items you migrate and to change the values as you wish
Personalizing Profiles
Besides working with anonymous users from theGlobal.asaxfile, you can also programmatically
personalize the profiles retrieved from the personalization store This is done through the use of the
Profile_Personalizeevent An example use of this event is shown in Listing 15-19
Listing 15-19: Personalizing a retrieved profile
VB
Public Sub Profile_Personalize(sender As Object, args As ProfileEventArgs)
Dim checkedProfile As ProfileCommon
If User Is Nothing Then Return
checkedProfile = CType(ProfileBase.Create(User.Identity.Name), ProfileCommon)
If (Date.Now.IsDaylightSavingTime()) Then
checkedProfile = checkedProfile.GetProfile("TimeDifferenceUser")
Else
checkedProfile = checkedProfile.GetProfile("TimeUser")
End If
If Not checkedProfile Is Nothing Then
args.Profile = checkedProfile
End If
End Sub
C#
public void Profile_Personalize(object sender, ProfileEventArgs args)
{
ProfileCommon checkedProfile;
if (User == null) { return; }
checkedProfile = (ProfileCommon)ProfileBase.Create(User.Identity.Name);
if (DateTime.Now.IsDaylightSavingTime()) {
checkedProfile = checkedProfile.GetProfile("TimeDifferenceUser");
Continued
Trang 8else {
checkedProfile = checkedProfile.GetProfile("TimeUser");
}
if (checkedProfile != null) {
args.Profile = checkedProfile;
}
}
In this case, based on a specific parameter (whether it is Daylight Savings Time or something else), you
are able to assign a specific profile to the user You do this by using theProfileModule.Personalize
event, which you would usually stick inside theGlobal.asaxpage
Determining Whether to Continue with Automatic Saves
When you are working with the profile capabilities provided by ASP.NET, the page automatically saves
the profile values to the specified data store at the end of the page’s execution This capability, which
is turned on (set totrue) by default, can be set tofalsethrough the use of theautomaticSaveEnabled
attribute in the<profile>node in theweb.configfile This is illustrated in Listing 15-20
Listing 15-20: Working with the automaticSaveEnabled attribute
<profile automaticSaveEnabled="false">
<properties>
<add name="FirstName" />
<add name="LastName" />
<add name="LastVisited" />
<add name="Age" />
<add name="Member" />
</properties>
</profile>
If you have set theautomaticSaveEnabledattribute value tofalse, you will have to invoke the
Profile-Base.Save()method yourself In most cases though, you are going to leave this setting ontrue Once a
page request has been made and finalized, theProfileModule.ProfileAutoSavingevent is raised This
is an event that you can also work with, as shown in Listing 15-21
Listing 15-21: Using the ProfileAutoSaving event to turn off the auto-saving feature
VB
Public Sub Profile_ProfileAutoSaving(sender As Object, _
args As ProfileAutoSaveEventArgs)
If Profile.PaidDueStatus.HasChanged Then
args.ContinueWithProfileAutoSave = True
Else
Trang 9args.ContinueWithProfileAutoSave = False
End If
End Sub
C#
public void Profile_ProfileAutoSaving(object sender, ProfileAutoSaveEventArgs args)
{
if (Profile.PaidDueStatus.HasChanged)
args.ContinueWithProfileAutoSave = true;
else
args.ContinueWithProfileAutoSave = false;
}
In this case, when theProfile_ProfileAutoSavingevent is triggered, it is then possible to work
within this event and change some behaviors Listing 15-21 looks to see if theProfile.PaidDueStatus
property has changed If it has changed, the auto-saving feature of the profile system is continued; if the
Profile.PaidDueStatushas not changed, the auto-saving feature is turned off
Personalization Providers
As shown in Figure 15-1 earlier in the chapter, the middle tier of the personalization model, the person-alization API layer, communicates with a series of default data providers By default, the personperson-alization model uses Microsoft SQL Server Express Edition files for storing the personalization properties you
define You are not limited to just this type of data store, however You can also use the Microsoft SQL
Server data provider to allow you to work with Microsoft SQL Server 7.0, 2000, 2005, and SQL Server
2008 Besides the Microsoft SQL Server data provider, the architecture also allows you to create your
own data providers if one of these data stores does not fit your requirements
Working with SQL Server Express Edition
The Microsoft SQL Server data provider does allow you to work with the new SQL Server Express Edition files The SQL Server data provider is the default provider used by the personalization system provided
by ASP.NET When used with Visual Studio 2008, the IDE places theASPNETDB.MDFfile within your
application’sApp_Datafolder
As you look through themachine.configfile, notice the sections that deal with how the personalization engine works with this database In the first reference to theLocalSqlServerfile, you find a connection string to this file (shown in Listing 15-22) within the<connectionStrings>section of the file
Listing 15-22: Adding a connection string to the SQL Server Express file
<configuration>
<connectionStrings>
<clear />
<add name="LocalSqlServer"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
Trang 10In this example, you see that a connection string with the nameLocalSqlServerhas been defined.
The location of the file, specified by theconnectionStringattribute, points to the relative path of the
file This means that in every application you build that utilizes the personalization capabilities, the
default SQL Server provider should be located in the application’sApp_Datafolder and have the name of
ASPNETDB.MDF
The SQL Server Express file’s connection string is specified through theLocalSqlServerdeclaration
within this<connectionStrings>section You can see the personalization engine’s reference to this in
the<profile>section within themachine.configfile The<profile>section includes a subsection
listing all the providers available to the personalization engine This is shown in Listing 15-23
Listing 15-23: Adding a new SQL Server data provider
<configuration>
<system.web>
<profile>
<providers>
<add name="AspNetSqlProfileProvider"
connectionStringName="LocalSqlServer" applicationName="/"
type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</profile>
</system.web>
</configuration>
From this, you can see that a provider is added by using the<add>element Within this element, the
connectionStringNameattribute points to what was declared in the<connectionString>attribute
from Listing 15-22
You can specify an entirely different Microsoft SQL Server Express Edition file other than the one
speci-fied in themachine.configfile First, create a connection string that points to a new SQL Server Express
file that is a templated version of theASPNETDB.mdbfile At this point, you can use<connectionString>
to point to this new file If you change these values in themachine.configfile, all the ASP.NET
appli-cations that reside on the server will then use this specified file If you make the changes only to the
web.configfile, however, only the application using this particularweb.configfile uses this new data
store Other applications on the server remain unchanged
Working with Microsoft’s SQL Server
7.0/2000/2005/2008
You will likely find it quite easy to work with the personalization framework using the SQL Server
Express files But when you work with larger applications that require the factors of performance and
reliability, you should use the SQL Server personalization provider along with SQL Server 7.0, 2000, 2005,
or 2008 If this data store is available, you should always try to use this option instead of the default SQL
Server Express Edition files