0% found this document useful (0 votes)
88 views

Implementing User Profiles in ASP

This document provides an introduction and tutorial on implementing user profiles in ASP.NET. It discusses why user profiles are useful, how to configure the profile provider, define profile properties, access and save profile data, and shows a basic sample application that remembers a user's name and last visit date using profiles. The profiles functionality allows websites to personalize the experience for returning users without needing to write custom code to store and retrieve user preferences.

Uploaded by

Project ICT
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
88 views

Implementing User Profiles in ASP

This document provides an introduction and tutorial on implementing user profiles in ASP.NET. It discusses why user profiles are useful, how to configure the profile provider, define profile properties, access and save profile data, and shows a basic sample application that remembers a user's name and last visit date using profiles. The profiles functionality allows websites to personalize the experience for returning users without needing to write custom code to store and retrieve user preferences.

Uploaded by

Project ICT
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

Implementing User Profiles in ASP.

NET - A Beginner's Guide

By Rahul Rajat Singh, 4 Sep 2012

4.25 (4 votes)

Download demo - 606.6 KB

Introduction

Background

using the Code

Understanding the Basics

Configuring the Profile Provider

Specifying the User Profile Properties

Accessing and Saving the Profile information

Get our sample Application to work

A note on Cookies

Points of Interest

History

Introduction

This article discusses the basic of User Profiles. Why do we need user profiles and how to implement
user profiles in ASP.NET.

Background
Websites that provide users a possibility to customize the look and feel of a website are often liked by
the user. It gives a little personal touch to the web site from a users' perspective.

ASP.NET themes is one way to provide users an option to change the appearance of the website. The
other important aspect of it is remembering a returning user and show him a customized layout based
on his preferences.

User profiles are used to achieve the same. Using profiles we can remember the user between visits and
display the appropriate layout/information to him.

Using the code

Understanding the Basics

To implement user profiles we need to specify a some things. Typical process of implementing User
profiles will follow the below mentioned steps

First we need to specify where the user profile will be saved. this can be done by specifying the Profile
Provider.

Once we have the Profile provider configured, we need to decide what information we need to save
for the user i.e. we need to define the user profile.

After this we need a mechanism to identify the user uniquely. This is easy if the user is a member of
our site but it gets tricky when we want to track all the anonymous users too.

Once we have identified the users uniquely we need to take his preferences and store them in our
profile provider.

Last but not the lease we need a way to identify the returning users and change the site's layout as
per his saved preferences.

Let us now develop a small application that will remember the user's name and the time of his last visit.
The default settings of profile is such that it will work only for authenticated users i.e. only for the
members of the site. we will see how to do this for the anonymous users. then we will see how we can
change this to use the authenticated users.

Note: This application will contain a single page website to demonstrate the User profiles. Typical real
world usage of user profile will be on a larger scale and perhaps it will be used in conjunction with
ASP.NET themes and/or web parts.

Configuring the Profile Provider

The profile provider specifies the store where the user preferences will be stored. Typically this is
SqlServer database. This needs to be done in the web.config file.

Collapse | Copy Code

<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>

The settings above shows the default profile provider which is SqlServer database placed in the
App_Data directory of the website. If we need to specify the custom profile provider then we need to
specify the connectionString intead of connectionStringName to use the appropriate database.

Also, we need to set the database to accept and save the profile related data. this can be done by
running the aspnet_regsql command against the database that needs to be used to save the profiles'
data.

Specifying the User Profile Properties


Now we have the provider configured, we need to specify the data that we need to save for the users.
We can do this by having the properties in the provider element of web.config. So let us create the
entries in web.config to track the required information that we discussed above.

Collapse | Copy Code

<profile>

<properties>

<add name="Name" allowAnonymous="true"/>

<add name="VisitedOn" type="System.DateTime" allowAnonymous="true"/>

</properties>

</profile>

The allowAnonymous="true" specifies that the anonymous users should also be able to save their profile
information. For this to work properly we need to specify <anonymousIdentification enabled="true"/> in
the web.config file.

Once we are done with this we have successfully defined what all properties we need to track as the
user profile information and it will work for authenticated as well as anonymous users.

Accessing and Saving the Profile information

Once we have done this the ASP.NET framework will create strongly type properties for each of our
profile properties. If we need to access these profile properties we can use the Profile.<PropertyName>
syntax to do so. If we need to access the properties we defined above all we need to do

Collapse | Copy Code

string name = Profile.Name;

DateTime lastVisited = Profile.VisitedOn;


The other part of it is saving the Profile information. To do that we can simply assign the new values to
these properties and make our changes permanent by calling Profile.Save(). Lets see how this can be
done with our properties.

Collapse | Copy Code

Profile.Name = TextBox1.Text;

Profile.VisitedOn = DateTime.Now;

Profile.Save();

The important thing to note while accessing the profiles is that if user has not saved his values yet then
they will result the default values of their respective types.

Get our sample Application to work

In the application that we are writing we will show the username and the time of his last visit. For the
first visit both of them will be default values. From the next time onwards, if the user has saved his
name then it will show the name otherwise it will simply show the time of last visit.

Let us see the design view of our page:

Now let us put all the above seen code to achieve the desired functionality, this is how our code behind
will look like:

Collapse | Copy Code

protected void Page_Load(object sender, EventArgs e)

if (IsPostBack == false)

{
string name = Profile.Name;

DateTime lastVisited = Profile.VisitedOn;

if (name == string.Empty)

//User has not specified his name

Label1.Text = "Guest";

else

//returning user, show his name

Label1.Text = name;

if (lastVisited.ToString() == "1/1/0001 12:00:00 AM")

Label2.Text = "Never";

else

Label2.Text = lastVisited.ToString();

}
protected void Page_UnLoad(object sender, EventArgs e)

Profile.VisitedOn = DateTime.Now;

Profile.Save();

protected void Button1_Click(object sender, EventArgs e)

Profile.Name = TextBox1.Text;

Profile.Save();

Label1.Text = TextBox1.Text;

Let us now run the page for the first time:

Lets now save our preferences and run it again:

So this time we can see that it remembered the name I saved and also shows me the last access time.
The User profiles have been configured and working fine now.

A note on Cookies

All the user profiles functionality that we have seen can also be done using cookies. Doing that will give
complete control in developers hands. in fact ASP.NET actually uses cookies to track the visits of
anonymous user. SO if we are saving the profiles for anonymous user and user decide to delete his
cookies then his preferences will not be accessible to him i.e. he will not be identified as a returning
user.

Points of Interest
User profiles provide a very good way of identifying the returning users. Cookies can also be used for the
same thing. But using Profiles we don't have to write that much code that we would have to write if we
use cookies. Also This approach is less error prone and using cookies. But I still think that knowing all
about cookies in details is a very must thing for a web developer. Perhaps I will talk about cookies in a
separate article.

This article is written from the perspective of absolute beginners. I hope this has been informative.

History

12 July 2012: First Version

License

This article, along with any associated source code and files, is licensed under The Code Project Open
License (CPOL)

About the Author

A Simple Profile

The Profile provider in ASP.NET stores and retrieves information about our site’s users. The default
profile provider keeps data in SQL Server tables. All we need to provide is a definition of the user profile.
The profile definition lives in the application’s web.config file. The following is a simple profile with
name and age properties.

<?xml version="1.0"?>
<configuration>

<system.web>

<anonymousIdentification enabled="true"/>

<trust level="Medium"/>

<profile >

<properties>

<add name="Name" allowAnonymous="true" />

<add name="Age" allowAnonymous="true" type="System.Int16"/>

</properties>

</profile>

<compilation debug="true"/>

</system.web>

</configuration>

Using the profile we’ve defined is straightforward. The following is a content page that will read the
current user’s profile settings into TextBox controls, and update the profile if the user clicks an update
button. Notice we don’t need to use any database access code or explicitly load or save profile settings –
ASP.NET takes care of all this work in the background.

<%@ Page Language="C#" MasterPageFile="~/Layout1.master" %>

<script runat="server">

protected void Page_Load(object sender, EventArgs e)

{
if (!IsPostBack)

nameTextBox.Text = Profile.Name;

ageTextBox.Text = Profile.Age.ToString();

protected void updateProfileButton_Click(object sender,

EventArgs e)

Profile.Name = nameTextBox.Text;

Profile.Age = Int16.Parse(ageTextBox.Text);

</script>

<asp:Content ID="Content1" ContentPlaceHolderID="main" runat="Server">

<hr />

<asp:TextBox runat="server" ID="nameTextBox" /><br />

<asp:TextBox runat="server" ID="ageTextBox" /><br />

<asp:Button runat="server" ID="updateProfileButton"

Text="Save Preferences"

OnClick="updateProfileButton_Click" />

</asp:Content>
The above sample works even for anonymous users. We will take a look later in the article how the
system tracks unnamed users, but for now let’s introduce the software behind the curtain.

The Profile Provider

SqlProfileProvider

The ASP.NET team implemented the profile management features using a provider model. A base
ProfileProvider class defines the interface, or contract, that all profile providers must implement.
ASP.NET 2.0 ships with an implementation of the ProfileProvider that uses SQL Server – the
SqlProfileProvider class. SqlProfileProvider implements the ProfileProvider methods (like
FindProfilesByUserName) by executing stored procedures in SQL Server.

The provider model is extensible. If you don’t want to use SQL Server, but want to use an XML file or a
different relational database engine, you can define your own class derived from the ProfileProvider
class and implement all the Profile features using a different data store. The beauty of the provider
model is how you can plug your own implementation of a feature into the system, and the runtime and
application continue to work without knowing the details of the implementation. Later in the article, we
will discuss the provider configuration. For now, let’s take a closer look at configuring Profile properties
in web.config.

Profiles, Users, Values

Let’s extend our Profile settings with the following web.config.

<profile >

<properties>

<add name="Name" allowAnonymous="true" />

<add name="Age" allowAnonymous="true" type="System.Int16"/>

<group name="UI">

<add name="MasterPage" defaultValue="layout1.master"/>

<add name="Theme" defaultValue="Red"/>


</group>

</properties>

</profile>

The above configuration demonstrates several features. First, Profile properties use the String type by
default. We can change the default with the type attribute, as we do with the Age property (typed as
Int16). We can define a default value for a profile property with the defaultValue attribute. The provider
will use the default value when a property value does not yet exist in the data store.

The Unidentified User

By default, Profile properties are only available for authenticated users. If we want a property to be
available for an anonymous user, we need to add allowAnonymous=”true” to the property. Without the
attribute, the runtime will throw an exception if the current user is anonymous and we write to the
property.

In order for allowAnonymous to work, we need to configure ASP.NET to track anonymous users. We
configure tracking using the anonymousIdentification section of web.config. Anonymous user tracking is
off by default, but enabled=”true” will tell the ASP.NET runtime to load an
AnonymousIdentificationModule into the HttpModule request pipeline. When an anonymous user
makes a request, this module creates a globally unique identifier using the System.Guid class, and writes
the GUID into a persistent cookie named .ASPXANONYMOUS. The GUID will be the anonymous user’s
“name”. Using a persistent cookie means the user’s GUID will be available between visits. The cookie
name, cookie timeout, and other characteristics of anonymous user tracking are configurable in the
anonymousIdentification configuration element.

Groupings

We can create a hierarchy of profile properties using the group element. Grouping allows us to
categorize properties, which can be helpful when there are a large number of profile properties. We can
specify more than one property group, but we cannot nest a group beneath another group element. As
you may have noticed in our first code sample, the ASP.NET compiler generates a class with strongly
typed profile properties. A grouping adds an additional layer in the generated class, as can be seen in
the following code snippet.
Profile.Name = "scott";

Profile.UI.Theme = "Reddish";

Profile.UI.MasterPage = "layout1.master";

Profiles At Compilation and Runtime

Where does the strongly typed Profile come from? The ASP.NET compiler parses web.config to uncover
the profile schema defined inside, and then code-generates a class in the Temporary ASP.NET Files
directory. The following class is an excerpt of the class generated from the web.config in this article.

public class ProfileCommon : System.Web.Profile.ProfileBase {

public virtual short Age

get

return ((short)(this.GetPropertyValue("Age")));

set

this.SetPropertyValue("Age", value);

// other properties ...

}
The above class (ProfileCommon) will compile into the App_Code assembly, meaning the class is visible
to all of our web forms, user controls, master pages, and to any classes in the App_Code directory. We
can use the Profile object from a base page class in App_Code:

using System;

using System.Web;

using System.Web.UI;

public class BasePage : Page

public BasePage()

PreInit += new EventHandler(BasePage_PreInit);

void BasePage_PreInit(object sender, EventArgs e)

ProfileCommon profile = HttpContext.Current.Profile

as ProfileCommon;

if (!String.IsNullOrEmpty(profile.UI.MasterPage))

MasterPageFile = profile.UI.MasterPage;

}
if (!String.IsNullOrEmpty(profile.UI.Theme))

Theme = profile.UI.Theme;

The above class sets the layout and look of a page based on a user’s preferences. Notice we can pull the
Profile object out of the current HttpContext object. There is another HttpModule in the pipeline, the
ProfileModule, which creates the Profile object during the AcquireRequestState event of the request
processing lifecycle. The ProfileModule places the ProfileCommon object into the current HttpContext
so the object is available for the duration of the request.

Notice we need to coerce the Profile object into a ProfileCommon reference (the as ProfileCommon in
the code). Since the ProfileCommon class is generated by ASP.NET from web.config, so it’s not possible
for the HttpContext class to know the definition of ProfileCommon. HttpContext has to return a
ProfileBase reference. The ProfileCommon class derives from ProfileBase. All we need to do is cast the
ProfileBase reference to a ProfileCommon reference.

Why doesn’t our web form code need to use the same type cast? The answer is that the ASP.NET
compiler code-generates a Profile property into our web form. If you poke around at the generated code
in the Temporary ASP.NET Files directory (with debug enabled), you’ll find each web form has a property
defined like the following:

protected ProfileCommon Profile {

get {

return ((ProfileCommon)(this.Context.Profile));

}
Our web form also pulls the profile object from the current HttpContext and casts the value to a
ProfileCommon reference. Since the ASP.NET compiler is kind enough to generate this code, we don’t
need to cast the reference in our web form code.

If we want to use the ProfileBase object in a class library outside the web application, however, we will
not be able to see the definition for the ProfileCommon class. You can still use a ProfileBase reference
from a class library project and read write properties using the GetPropertyValue and SetPropertyValue
methods of ProfileBase. Another solution might be to use Profile inheritance, which we will look at later
in the article.

Provider Configuration

The machine.config file configures the default Profile provider for all web sites on the computer. The
machine.config file is located in the framework installation config directory, typically
Windows\Microsoft.NET\Framework\v2.0.xxxx\Config. Inside is the following.

<profile>

<providers>

<add name="AspNetSqlProfileProvider"

connectionStringName="LocalSqlServer"

applicationName="/"

type="System.Web.Profile.SqlProfileProvider />

</providers>

</profile>

The LocalSqlServer connection string points to a SQL Server 2005 Express database in the application’s
App_Data folder. You can create a database on a different instance of SQL Server, or on a remote SQL
Server, using the ASP.NET Sql Server Registration Tool (aspnet_regsql.exe). With a new database in
place, you can either replace the LocalSqlServer connection string in your application’s web.config file,
or reconfigure the provider to use a different connection string name. The following replaces the
LocalSqlServer connection string to point to a different server.
<configuration>

<connectionStrings>

<remove name="LocalSqlServer"/>

<add name="LocalSqlServer"

connectionString="server=goa;database=aspnetdb;integrated security=sspi;"

/>

</connectionStrings>

...

</configuration>

The following configures a the SqlProfileProvider using a connection string named MySqlServer.

<profile defaultprovider="MyProfileProvider">

<providers>

<add name="MyProfileProvider"

connectionStringName="MySqlServer"

applicationName="/"

type="System.Web.Profile.SqlProfileProvider" />

</providers>

</profile>

For the configuration to work, you’ll need to create a MySqlServer connection string in web.config. Note
also that the account logging into SQL Server will need permission to access the profile related tables
and stored procedures. ASP.NET creates several roles in the database, including the
aspnet_Profile_BasicAccess role, which grants all the permissions required for creating, updating, and
deleting profiles.

Serialization
The runtime serializes primitive Profile properties (like strings, integers, and DateTime instances) as
strings. We can override serialization behavior with the serializeAs attribute and select the XmlSerializer
(serializeAs="Xml") or the BinarySerializer (serializeAs="Binary"). The default serializer is the
XmlSerializer. Let’s say we want to keep track of a user’s favorite Pet with the following class in
App_Code:

using System;

public class Pet

public Pet()

// default ctor required for serializer

public Pet(string name)

_name = name;

private string _name = String.Empty;

public string Name

get { return _name; }

set { _name = value; }

}
}

Notice we need a default constructor for our class to work with serialization. We can add a favorite Pet
into the profile by first adding a new property into web.config:

<add name="Pet" allowAnonymous="true" type="Pet"/>

If we put the following code into a web form’s Page_Load method, the runtime will serialize the Pet
object into the database as XML (the default).

protected void Page_Load(object sender, EventArgs e)

Profile.Pet = new Pet("Beaker The Cat");

You can look in the dbo.aspnet_Profile table to see serialized profiles. String and XML properties will be
in the PropertyValuesString column, while objects serialized into binary will appear in the
PropertyValuesBinary column. Side note: you’ll never want to store sensitive information into a user’s
profile without encrypting the data first. Information in the profile columns is easy to extract.

Looking at the PropertyValuesString column in the aspnet_Profile table for our user's record, we will find
the following (amongst the other property values).

<?xml version="1.0" encoding="utf-16"?>

<Pet

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<Name>Beaker The Cat</Name>

</Pet>

If we want to use a binary serializer with Pet objects, we could change the property configuration as
follows:

<add name="Pet" allowAnonymous="true" type="Pet"

serializeAs="Binary"/>

The above configuration will throw an error: “The type for the property 'Pet' cannot be serialized using
the binary serializer, since the type is not marked as serializable”. We need to make one small
adjustment to the Pet class:

using System;

[Serializable]

public class Pet

// ...

Our pet objects will now appear as binary data in the PropertyValuesBinary column.

Profile Inheritance

The Profile object can inherit from an existing class. For example:
using System;

using System.Web.Profile;

using System.Collections.Generic;

public class CustomProfile : ProfileBase

[SettingsAllowAnonymous(true)]

public string Name

get { return base["Name"] as string; }

set { base["Name"] = value; }

[SettingsAllowAnonymous(true)]

public int Age

get { return (int)base["Age"]; }

set { base["Age"] = value; }

[SettingsAllowAnonymous(true)]

public List<Pet> Pets

get { return base["Pets"] as List<Pet>; }

set { base["Pets"] = value; }


}

A Profile class has to derive from ProfileBase. The public properties in the CustomProfile class forward
calls to the ProfileBase indexer ([] in C#, () in VB). The base class will interact with the Profile provider to
retrieve the values we need. Notice the class even uses a generic collection to store a list of all the user’s
pets. To use the class, we just need to reconfigure our profile settings in web.config and use the inherits
attribute.

<profile inherits="CustomProfile">

<properties>

<add name="LuckyNumber" allowAnonymous="true"

type="System.Int32" defaultValue="7" />

</properties>

</profile>

Notice we can still augment the properties of our CustomProfile class with additional properties in
web.config. The following code puts the new Profile to work.

Profile.LuckyNumber = 21;

Profile.Pets = new List<Pet>();

Profile.Pets.Add(new Pet("Dolly the Dolphin"));

Profile.Pets.Add(new Pet("Bessie the Cow"));

One good reason to inherit from a custom base class is that we can add additional logic to the Profile
object. For instance, we can add validation logic to the Age property to ensure the user provides us with
a sensible age, and not a value like 443.

Migrating Anonymous User Settings


If your web application allows anonymous users to set Profile properties, and your web application
includes not only authenticated but anonymous users, then there is a sticky scenario to handle. At some
point an anonymous user might login and become an authenticated user. After a user authenticates,
their Profile changes, because the Profile system keys Profile information by username.

At the point an anonymous user changes to an authenticated user, the Profile module gives us a chance
to migrate the user’s anonymous profile to the new authenticated profile with a MigrateAnonymous
event. We can handle this global event in global.asax with the following code.

void Profile_MigrateAnonymous(object sender,

ProfileMigrateEventArgs e)

ProfileCommon anonProfile =

Profile.GetProfile(e.AnonymousID);

Profile.Age = anonProfile.Age;

Profile.LuckyNumber = anonProfile.LuckyNumber;

Profile.Pets = anonProfile.Pets;

AnonymousIdentificationModule.ClearAnonymousIdentifier();

It is important to tell the AnonymousIdentificationModule to clear the anonymous identifier (the


cookie). Without this call the event will continue to fire with each page the authenticated user visits.

The MigrateAnonymous event isn’t perfect, however, because it will fire each time an anonymous user
logs in – even if we migrated their anonymous profile on a previous visit. If you want to prevent a user
from overwriting their authenticated profile with inadvertent changes to their anonymous profile, you
should consider adding a boolean flag to the profile, and migrate the profile settings only when the flag
is false (then set the flag to true).

The ProfileManager

ProfileManager

discussion of Profiles would be complete without mentioning the ProfileManager class. The
ProfileManager class is useful for managing profiles. Since the class is a static class, all the members are
available to call without creating an instance of the class. The class is useful for managing profiles
(ProfileManager.DeleteInactiveProfiles, for example), and for reporting on profiles. The GetAllProfiles
method, for instance, includes an overload which accepts paging parameters (pageSize, pageIndex). The
DeleteInactiveProfiles method will clean up profile records that have not been touched since a certain
date.

You might also like