An Extended Look at the Profile Object - Part 2
 
Published: 24 Oct 2005
Unedited - Community Contributed
Abstract
This article is the second article in the series of articles on the new personalization feature of ASP.NET 2.0, the Profile object. The Profile object allows the web application to store data for each visitor to the application, save that data to a storage medium like Microsoft SQL Server, and then retrieve the data when the same visitor returns to the application. The first article looked at the basics of Profile object, and showed how it can use simple and grouped properties configured in the application's configuration file (web.config). But the Profile object is not limited to using simple and grouped properties. This article will examine two ways of using custom objects with the Profile object.
by Bilal Haidar
Feedback
Average Rating: 
Views (Total / Last 10 Days): 27431/ 33

Introduction

This article is the second article in the series of articles on the new personalization feature of ASP.NET 2.0, the Profile object. The Profile object allows the web application to store data for each visitor to the application, save that data to a storage medium like Microsoft SQL Server, and then retrieve the data when the same visitor returns to the application.

The first article looked at the basics of the Profile object, and showed how it can use simple and grouped properties configured in the application's configuration file (web.config). But the Profile object is not limited to using simple and grouped properties. This article will examine two ways of using custom objects with the Profile object.

In the previous article, we explained the basics of the Profile object and provided an example on how to use simple and grouped properties as part of the Profile object. The following configuration section shows how we can use simple properties with the Profile object.

Listing 1: Simple Profile Property Configuration

<configuration>
<system.web>
<authentication mode="forms" />
<anonymousIdentification enabled="true" />
<profile enabled="true">
<properties>
<add name="FirstName" defaultValue="Bilal" type="string" 
allowAnonymous="true" />
<add name="LastName" defaultValue="Haidar" type="string" allowAnonymous="true" />
</properties>
</profile>
</system.web>
</configuration>

In the above listing, we define two simple properties, FirstName and LastName, both of type string and each with a default value.

As you can see, it is an easy matter to add simple properties to the Profile object. However, in more advanced applications, we need to use our own custom objects with the Profile object. We do not want to decompose our custom object so that it can be represented by a group of simple properties; we want to be able to store our custom object in the Profile object. How is this done? That is one of the topics of this article.

Specifying a Custom Object in the Profile Configuration Section

Suppose we are developing an application for teachers in a school that tracks which of its students have registered for a certain event in the school. A teacher should be able to add a student to the list of those participating in the event, remove a student, and so on.

For this functionality, we will create a StudentList class that is a collection of Student types. A teacher can add and remove any student from the StudentList collection. Storing this class in a Profile object means that the student list will be available automatically every time the teacher logs in to his or her account.

Listing 2 shows a Profile configuration section that defines a Profile property whose type refers to a class of type StudentList. In addition, we see a new serializeAs attribute that is used to persist the StudentList class using binary serialization.

Listing 2. Profile Configuration Section with a Custom Object

<anonymousIdentification enabled="true"/>
<Profile enabled="true">
<properties>
<add name="StudentList" type="StudentList" allowAnonymous="true" serializeAs="Binary" />
</properties>
</Profile>

Listing 3 shows the code for the implementation of the StudentList class. This class has methods to add and remove student records from the list. It also contains a property that represents the number of students’ records in the student list.

Listing 3. StudentList

using System;
using System.Collections;
[Serializable]
public class StudentList : IEnumerable
{
private Hashtable _StudentRecords = new Hashtable();
//Return Student Records
public Hashtable StudentRecords
{
get { return _StudentRecords; }
}
// Return the number of student records in the student list
public int AllRecords
{
get
{
int Count = 0;
foreach (StudentRecord sr in _StudentRecords.Values)
{
Count++;
}
return Count;
}
}
// Add a new Student Record to the student list
public bool AddRecord(int StudentId, StudentRecord sr)
{
StudentRecord _SR = (StudentRecord)_StudentRecords[StudentId];
if (_SR == null)
{
_StudentRecords.Add(StudentId, sr);
return true;
}
// Student record is already in the list
return false;
}
// Remove a student record from the list if found
public bool RemoveRecord(int StudentId)
{
StudentRecord _SR = (StudentRecord)_StudentRecords[StudentId];
if (_SR == null)
{
// The record to be deleted is not in the list.
return false;
}
// Student record is in the list
_StudentRecords.Remove(StudentId);
return true;
}
// Allow to use foreach by implementing the IEnumerable Interface.
public IEnumerator GetEnumerator()
{
for ( int i = 1; i <= _StudentRecords.Count; i++ )
yield return _StudentRecords[i];
}
}

As we have seen in the above listing, we have used a custom object called StudentRecord which represents one student record. Listing 4 below presents the implementation of that custom object.

Listing 3. StudentRecord

using System;
using System.Data;
using System.Configuration;
[Serializable]
public class StudentRecord
{
#region Private Fields
private int _StudentId;
private string _FirstName;
private string _LastName;
#endregion
#region Constructor
public StudentRecord(int StudentId, string FirstName, string LastName)
{
_StudentId = StudentId;
_FirstName = FirstName;
_LastName = LastName;
}
#endregion
#region Properties
public int StudentId
{
get { return _StudentId; }
}
public string FirstName
{
get { return _FirstName; }
}
public string LastName
{
get { return _LastName; }
}
#endregion
}

The above two classes should be placed in the App_Code directory, which is a system directory that contains all custom objects created in the Web application. This directory will be compiled into a single DLL at runtime and all the custom objects placed inside it will be accessible to all the ASP.NET pages in the application.

Also notice that each class has an attribute of Serializable. This attribute should be set because both objects must be serialized in order to be stored in a Profile object.

Listing 5 presents the page that allows each teacher to add a new student record to the StudentList (See Figure 1).

Figure 1. Add Record

Listing 5. AddRecord.aspx

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class AddRecord : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder1.Visible = false;
}
protected void Button1_Click(object sender, EventArgs e)
{
// New instance of StudentRecord
StudentRecord sr = null;
// Studen record
int _Id;
bool TempId = int.TryParse( TextBox3.Text, out _Id );
if (TempId && 
!string.IsNullOrEmpty(TextBox1.Text) &&
!string.IsNullOrEmpty(TextBox2.Text)
}
sr = new StudentRecord(_Id, TextBox1.Text, TextBox2.Text);
else
// If one of the field are wrong we return 
// and don’t insert the record
return;
// Initialize the list if empty
if (Profile.StudentList == null)
Profile.StudentList = new StudentList();
// Show Place holder
PlaceHolder1.Visible = true;
// Add student record to list
if (Profile.StudentList.AddRecord(_Id, sr))
{
// Display the Profile proeprties 
string TextToDisplay = "Student with Id <b>" + _Id + "</b> is added to the list <br />";
PlaceHolder1.Controls.Add(new LiteralControl(TextToDisplay));
PlaceHolder1.Controls.Add(new LiteralControl("<hr /><br />"));
}
else
PlaceHolder1.Controls.Add(new LiteralControl("Student is already in the list"));
}
}

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AddRecord.aspx.cs" Inherits="AddRecord" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "<a href="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd</a>">
<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" >
<head runat="server">
<title>Add Record Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div>
<h2>
Teacher Administration Area</h2>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<br />
<br />
Student Id :&nbsp;
<asp:TextBox ID="TextBox3" runat="server"></asp:TextBox><br />
<br />
First Name :
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<p>
Last Name :
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox></p>
<p>
&nbsp; &nbsp;
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Add User" /></p>
</div>
</div>
</form>
</body>
</html>

Listing 6 presents the page that allows each teacher to remove a student record from the StudentList (See Figure 2).

Figure 2. Remove Record

Listing 6. RemoveRecord.aspx

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class RemoveRecord : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder1.Visible = false;
}
protected void Button1_Click(object sender, EventArgs e)
{
// Studen record
int _Id;
bool TempId = int.TryParse(TextBox3.Text, out _Id);
// Show Palce holder
PlaceHolder1.Visible = true;
if (TempId)
{
// Add student record to list
if (Profile.StudentList.RemoveRecord(_Id))
{
// Display the Profile proeprties 
string TextToDisplay = "Student with Id <b>" + _Id + "</b> is removed from the list <br />";
PlaceHolder1.Controls.Add(new LiteralControl(TextToDisplay));
PlaceHolder1.Controls.Add(new LiteralControl("<hr /><br />"));
}
else
PlaceHolder1.Controls.Add(new LiteralControl("Student is not found in the list"));
}
else
PlaceHolder1.Controls.Add(new LiteralControl("Student Id is not a valid Id"));
}
}

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RemoveRecord.aspx.cs" Inherits="RemoveRecord" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "<a href="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd</a>">
<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" >
<head runat="server">
<title>Remove Record Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div>
<div>
<h2>
Teacher Administration Area - Remove Record</h2>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<br />
<br />
Student Id :&nbsp;
<asp:TextBox ID="TextBox3" runat="server"></asp:TextBox><br />
<p>
&nbsp; &nbsp;
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Remove Student" /></p>
</div>
</div>
</div>
</form>
</body>
</html>

Finally, the page in Listing 7 below displays a list of all students’ records that have been previously added using the AddRecord.aspx page (see Figure 1). We have looped through all the student records stored within the StudentList property of the Profile object and displayed them on the page.

Figure 3. Display StudentList records

Listing 7. Displaying StudentList records

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class DisplayRecords : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder1.Controls.Add(new LiteralControl("There are " + Profile.StudentList.AllRecords + " student(s) in the list: <br /><br/>"));
foreach (StudentRecord sr in Profile.StudentList)
{
PlaceHolder1.Controls.Add(new LiteralControl("Student Id : " + sr.StudentId + "<br />"));
PlaceHolder1.Controls.Add(new LiteralControl("First Name : " + sr.FirstName + "<br />"));
PlaceHolder1.Controls.Add(new LiteralControl("Last Name &nbsp;: " + sr.LastName + "<br /><hr /><br/>"));
}
}
}

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DisplayRecords.aspx.cs" Inherits="DisplayRecords" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "<a href="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd</a>">
<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" >
<head runat="server">
<title>Display All Student Records</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>
Teacher Administration Area - Display Records</h2>
<p>
&nbsp;</p>
<p>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
&nbsp;</p>
</div>
</form>
</body>
</html>

 

Inheriting a Profile

In a previous section we discussed one of the ways to use our custom object in the Profile object. In this final section of the article, we will show you how to create a custom object that inherits from the Profile base class which is ProfileBase class, then configure the Profile configuration section in the application’s configuration file (web.config) to inherit from that class.

As we know, at run time an instance of the ProfileCommon class, which inherits from the ProfileBase class, is dynamically created. Using the inherits property allows the automatically generated ProfileCommon class to be created by inheriting from a class specified within its value and not from the ProfileBase base class; this can be found in the System.Web.Profile namespace.

Listing 8 shows the code for the StudentRecordInherit class that inherits from the ProfileBase base class.

Listing 8. StudentRecordInherit Inheriting from ProfileBase

using System;
using System.Web.Profile;
public class StudentRecordInherit : ProfileBase
{
#region Private Fields
private int _StudentId;
private string _Fname;
private string _Lname;
#endregion
#region Property Section
public int StudentId
{
get { return _StudentId; }
set { _StudentId = value; }
}
public string FirstName
{
get { return _Fname; }
set { _Fname = value; }
}
public string LastName
{
get { return _Lname; }
set { _Lname = value; }
}
#endregion
}

Listing 9 presents the Profile configuration section. There is no need to add any property; only the inherits property should be assigned to a custom class inheriting from ProfileBase base class.

Listing 9. Profile configuration section using Inherits

<anonymousIdentification enabled="true"/>
<Profile enabled="true" inherits="StudentRecord" /> 

Listing 10 demonstrates the use of the Profile object when inheriting from a custom class. When using the inherits property, all the properties of the custom class would be properties of the Profile object, since the ProfileCommon is auto-generated from that custom class.

Figure 4. Testing Inherits Property

Listing 10. Testing Inherits Property

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Profile;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class TestInherits : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Profile.StudentId = 1;
Profile.FirstName = "Bilal";
Profile.LastName = "Haidar";
Response.Write("Student Id &nbsp;: " + Profile.StudentId + "<br />");
Response.Write("First Name : " + Profile.FirstName + "<br />");
Response.Write("Last Name : " + Profile.LastName + "<br />");
}
} 

We have seen two ways in which we can use our custom objects as part of the Profile object. Logically speaking, it would be better to go with the second option, in which we create our custom object inheriting from the ProfileBase class. This would give us full control over the properties which are part of the ProfileCommon instance created at run time.

Conclusion

In this second part of the series of article on the Profile object, we demonstrated the two ways of using our custom objects as part of the Profile object.

In the first, we added a property whose type is the custom object we have; in the second, we used the inherit field in the Profile configuration section.

In Part 3 of this series, we will look into more advanced features of the Profile object, mainly, how to manage the Web application profiles by using the different available methods in the System.Web.Profile namespace.

Happy Dot Netting!



User Comments

Title: Property IsDirty when inheriting ProfileBase (2nd option)   
Name: AiM
Date: 2006-07-20 11:33:35 AM
Comment:
I tried both versions, when I set the configuration in the config file it works ok, but when I implement the class that inherits from ProfileBase the changes aren't saved. I overrided the Save method just to check for the value of the IsDirty property, and it is false.
How this should work, are there other details for the inherited option I don't know?
Title: Re:   
Name: Bilal Haidar [MVP]
Date: 2005-12-01 5:21:55 AM
Comment:
Hello:
You should wait for Part3 of this series to know everything about the database and etc...

Regards
Title: Where is Database ?   
Name: Zeeshan Ali
Date: 2005-12-01 5:17:02 AM
Comment:
You didn't specify the database to which the profile will persist. Where the Peofile data is being persist ?? Cookies ? or What ?
Title: Win app   
Name: Anders H
Date: 2005-11-30 4:44:45 PM
Comment:
If you want to use this example, in a web app,you add data and work with it in a webb app, then you want to get this data in a windows service app for example mailing things based on the items in this profile data, then you need to get to this data from a win app, how do you do that???
Title: Re:   
Name: Bilal Haidar [MVP]
Date: 2005-11-30 1:29:12 AM
Comment:
Well, the Profile object has its own HttpModule events. The way it works is as follows:
At runtime, the configuration section of the profile object in the Web.config will be tranformed into a strongly typed object which is then added to the HttpContext.
At the beginning of the request, the profile data are loaded from database, then at the end of the request, if the data is dirty (has been changed) it will be saved back. Saving data at every request is a matter of a Flag you can configure.
Hope that answers you well.

Regards
Title: One of the more useful articles I've seen in a long time!   
Name: Colin
Date: 2005-11-29 6:12:03 PM
Comment:
I just learned how to create a custom Role- and Membership- Provider and I saw no mention of this class anywhere! I wish I'd known because I spent a long time digging for something like this, and ended up coming up with a custom implementation using an HttpModule and Session.

Have you discovered in your study of the class what the default persistance mechanism is the profile? Is it stored in the user's context or persisited, like forms authentication info, in a secured cookie or something?
Title: Re:   
Name: Bilal Haidar [MVP]
Date: 2005-11-29 1:51:35 AM
Comment:
Hi to all:
Profile object can be thought of as advanced session object. In windows applications, no need for that concept, so it is ot available there.
Thanks for the comments.

Regards
Title: good article   
Name: DotNETKans
Date: 2005-11-29 12:21:16 AM
Comment:
hi Bilal,

Good article mate. Keep it up.
Title: From a win32 app   
Name: Anders H
Date: 2005-11-28 12:39:01 PM
Comment:
How can i access this from an win32 application, it complain on profile object others than ordinary type eg. string, int etc....??

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-29 4:23:44 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search