6. Using Profile Properties
With these details in place,
you're ready to access the profile information using the Profile
property of the current page. When you run your application, ASP.NET
creates a new class to represent the profile by deriving from
System.Web.Profile.ProfileBase, which wraps a collection of profile
settings. ASP.NET adds a strongly typed property to this class for each
profile property you've defined in the web.config file. These strongly
typed properties simply call the GetPropertyValue() and
SetPropertyValue() methods of the ProfileBase base class to retrieve and
set the corresponding profile values.
For example, if you've defined a string property named FirstName, you can set it in your page like this:
Profile.FirstName = "Henry"
Figure 2
presents a complete test page that allows the user to display the
profile information for the current user or set new profile information.
The first time this page
runs, no profile information is retrieved, and no database connection is
used. However, if you click the Show Profile Data button, the profile
information is retrieved and displayed on the page:
Protected Sub cmdShow_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles cmdShow.Click
lbl.Text = "First Name: " & Profile.FirstName & "<br />" & _
"Last Name: " & Profile.LastName & "<br />" & _
"Date of Birth: " & Profile.DateOfBirth.ToString("D")
End Sub
At this point, an error
will occur if the profile database is missing or the connection can't be
opened. Otherwise, your page will run without a hitch, and you'll see
the newly retrieved profile information. Technically, the complete
profile is retrieved when your code accesses the Profile.FirstName
property in the first line and is used for the subsequent code
statements.
NOTE
Profile
properties behave like any other class member variable. This means if
you read a profile value that hasn't been set, you'll get a default
initialized value (such as an empty string or 0).
If you click the Set Profile Data button, the profile information is set based on the current control values:
Protected Sub cmdSet_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles cmdSet.Click
Profile.FirstName = txtFirst.Text
Profile.LastName = txtLast.Text
Profile.DateOfBirth = Calendar1.SelectedDate
End Sub
Now the profile
information is committed to the database when the page request finishes.
If you want to commit some or all of the information earlier (and
possibly incur multiple database trips), just call the Profile.Save()
method. As you can see, the profiles feature is unmatched for
simplicity.
The Profile object doesn't
just include the properties you've defined. It also provides the
properties LastActivityDate (the last time this profile was used) and
LastUpdatedDate (the last time this profile was changed), using
information drawn from the database.
|
|
7. Profile Serialization
Earlier, you learned how
properties are serialized into a single string. For example, if you
save a FirstName of Harriet and a LastName of Smythe, both values are
crowded together in the PropertyValuesString field of the aspnet_Profile
table in the database, like so:
HarrietSmythe
The PropertyNames field (also
in the aspnet_Profile table) gives the information you need to parse
each value from the PropertyValuesString field. Here's what you'll see
in the PropertyNames field in this example:
FirstName:S:0:7:LastName:S:7:6:
The colons (:) are used as delimiters. The basic format is as follows:
PropertyName:StringOrBinarySerialization:StartingCharacterIndex:Length:
Something interesting happens if you create a profile with a DateTime data type, like this:
<add name="DateOfBirth" type="System.DateTime" serializeAs="String"/>
<add name="FirstName" type="System.String" serializeAs="Xml"/>
<add name="LastName" type="System.String" serializeAs="Xml"/>
Now, when you look at the PropertyValuesString field, you'll see something like this:
<?xml version="1.0" encoding="utf-16"?><dateTime>2007-07-12T00:00:00-04:00
</dateTime>HarrietSmythe
Initially, it looks like
the profile data is serialized as XML, but the PropertyValuesString
clearly doesn't contain a valid XML document (because of the text at the
end). What has actually happened is that the first piece of
information, the DateTime, is serialized (by default) as XML. The
following two profile properties are serialized as ordinary strings.
The PropertyNames field makes it slightly clearer:
DateOfBirth:S:0:81:FirstName:S:87:7:LastName:S:94:6:
Interestingly, you have the
ability to change the serialization format of any profile property by
adding the serializeAs attribute to its declaration in the web.config
file. Table 3 lists your choices.
Table 3. Serialization Options
SerializeAs | Description |
---|
String | Converts the type to a string representation. Requires a type converter that can handle the job. |
Xml | Converts
the type to an XML representation, which is stored in a string, using
the System.Xml.XmlSerialization.XmlSerializer (the same class that's
used with web services). |
Binary | Converts
the type to a proprietary binary representation that only .NET
understands using the System.Runtime.Serialization.Formatters.Binary.
BinaryFormatter. This is the most compact option but the least flexible.
Binary data is stored in the PropertyValuesBinary field instead of the
PropertyValues. |
ProviderSpecific | Performs customized serialization that's implemented in a custom provider. |
For example, here's how you can change the serialization for the profile settings:
<add name="DateOfBirth" type="System.DateTime" serializeAs="String"/>
<add name="FirstName" type="System.String" serializeAs="Xml"/>
<add name="LastName" type="System.String" serializeAs="Xml"/>
Now the next time you set
the profile, the serialized representation in the PropertyValuesString
field will store information for FirstName and LastName. It takes this
form:
2007-06-27<?xml version="1.0" encoding="utf-16"?><string>Harriet</string>
<?xml version="1.0" encoding="utf-16"?><string>Smythe</string>
If you use the binary
serialization mode, the property value will be placed in the
PropertyValuesBinary field instead of the PropertyValuesString field.
Here's an example where the FirstName property is serialized in the
PropertyValuesBinary field:
<add name="DateOfBirth" type="System.DateTime" serializeAs="String"/>
<add name="FirstName" type="System.String" serializeAs="Binary"/>
<add name="LastName" type="System.String" serializeAs="String"/>
The only indication of this shift is the use of the letter B instead of S in the PropertyNames field (and the fact that fewer bytes of are required):
DateOfBirth:S:0:9:FirstName:B:0:31:LastName:S:9:64:
All of these serialization
details raise an important question—what happens when you change profile
properties or the way they are serialized? Profile properties don't
have any support for versioning. However, you can add or remove
properties with relatively minor consequences. For example, ASP.NET will
ignore properties that are present in the aspnet_Profile table but not
defined in the web.config file. The next time you modify part of the
profile, these properties will be replaced with the new profile
information. Similarly, if you define a profile in the web.config file
that doesn't exist in the serialized profile information, ASP.NET will
just use the default value. However, more dramatic changes—such as
renaming a property, changing its data type, and so on, are likely to
cause an exception when you attempt to read the profile information.
Even worse, because the serialized format of the profile information is
proprietary, you have no easy way to migrate existing profile data to a
new profile structure.
Not all types are
serializable in all ways. For example, classes that don't provide a
parameterless constructor can't be serialized in Xml mode. Classes that
don't have the Serializable attribute can't be serialized in Binary
mode. You'll consider this distinction when you contemplate how to use
custom types with profiles (see the "Profiles and Custom Data Types"
section), but for now just keep in mind that you may run across types
that can be serialized only if you choose a different serialization
mode.
|
|
8. Profile Groups
If you have a large number
of profile settings, and some settings are logically related to each
other, you may want to use profile groups to achieve better
organization.
For example, you may
have some properties that deal with user preferences and others that
deal with shipping information. Here's how you could organize these
profile properties using the <group> element:
<profile>
<properties>
<group name="Preferences">
<add name="LongDisplayMode" defaultValue="true" type="Boolean" />
<add name="ShowSummary" defaultValue="true" type="Boolean" />
</group>
<group name="Address">
<add name="Name" type="String" />
<add name="Street" type="String" />
<add name="City" type="String" />
<add name="ZipCode" type="String" />
<add name="State" type="String" />
<add name="Country" type="String" />
</group>
</properties>
</profile>
Now you can access the
properties through the group name in your code. For example, here's how
you retrieve the country information:
lblCountry.Text = Profile.Address.Country
Groups are really just a
poor man's substitute for a full-fledged custom structure or class. For
instance, you could achieve the same effect as in the previous example
by declaring a custom Address class. You'd also have the ability to add
other features (such as validation in the property procedures). The next
section shows how.