Strongly Typed Session Properties in ASP.NET
In many ASP.NET projects, it is very common to use the Session object to store and retrieve data that can be accessed from any page withing the current user session, we usually would do something like:
Session[“Username”] = “cintriago”;
int hits = (int) Session[“HitCount”] ;
Session[“HitCount”] = hits +1;
The above example is a common code section that you would write in your application, but how would you like to write it like this:
Profile.Username = “cintriago”;
Profile.HitCount++;
What do you think? in ASP.NET you can use strongly typed properties to read and write data shared across a user’s session. How?, keep reading…
Using strongly typed properties is actually not so difficult, and the best part is that we use ASP.NET framework functionality, specifically the “Profile” class (You can read more about ASP.NET Profile class here). ASP.NET uses the Profile class to save user’s specific data in SQL Server, but we can change the repository, in this case a static object!. We will use an example to illustrate how to do it:
Lets launch Visual Studio and create a new empty Web Site called “CustomASPNetProfile”, next add the “App_Code” special folder. Once ready lets create a repository store the information we need (our Model), we will create 2 classes SessionProfile and SessionProfileData:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class SessionProfile
{
public SessionProfile()
{
Properties = new List<SessionProfileData>();
}
public int ProfileId {get;set;}
public string Username {get;set;}
public string ApplicationName { get; set; }
public bool IsAnonymous { get; set; }
public DateTime LastActivity { get; set; }
public List<SessionProfileData> Properties { get; set; }
}
public class SessionProfileData
{
public SessionProfileData()
{
}
public object PropertyValue { get; set; }
public string PropertyName { get; set; }
}
The SessionProfile class represents each individual session in our application, that is why you can see a ProfileId property that uniquely identifies each object, we also store the Username and if the current user is logged in or not (ASP.NET security integration!, aint that cool?).
The SessionProfileData class will keep a list of all the properties that we are going to use as strongly type accessors for our repository.
Now it is time to build our custom Profile provider class called SessionProfileProvider that will inherit the System.Web.ProfileProvider class. Our new class needs to implement some methods (many of them will not be used in this example), but before going into that, let’s create the static object that will keep users data in memory:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Profile;
/// <summary>
/// Summary description for SessionProfileProvider
/// </summary>
public class SessionProfileProvider : ProfileProvider
{
private static List<SessionProfile> m_profiles;
public SessionProfileProvider()
{
//
// TODO: Add constructor logic here
//
}
}
In the above code, a “m_profiles” static member is created, we will use this object to read and write user data across the Web Site, let’s check the two main methods of this class: GetPropertyValues and SetPropertyValues
public override SettingsPropertyValueCollection GetPropertyValues(System.Configuration.SettingsContext context, System.Configuration.SettingsPropertyCollection collection)
{
string username = context["UserName"].ToString();
string applicationName = (null != context["ApplicationName"] ? context["ApplicationName"].ToString() : String.Empty);
bool isAnonymous = bool.Parse(context["IsAuthenticated"].ToString());
lock (m_profiles)
{
SessionProfile profile = m_profiles.Find(x => (x.Username == username)
&& (x.IsAnonymous == isAnonymous)
&& (x.ApplicationName == applicationName)
);
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
foreach (SettingsProperty prop in collection)
{
SessionProfileData profileProperty = null;
object value = null;
if (profile != null)
profileProperty = profile.Properties.Find(x => x.PropertyName == prop.Name);
if (profileProperty != null)
value = profileProperty.PropertyValue;
SettingsPropertyValue p = new SettingsPropertyValue(prop);
Type propType = p.PropertyValue.GetType();
if (propType == typeof(Int32) && value == null)
value = 0;
if (propType == typeof(bool) && value == null)
value = false;
p.PropertyValue = value;
values.Add(p);
}
return values;
}
}
In this method we iterate over the list of available properties (we will see how to dynamically define the list of available properties in the web.config file later) and for each one, get its corresponding value from the m_profiles list, finally a SettingsPropertyValueCollection object is returned with the properties and values.
Now let’s check the other method:
public override void SetPropertyValues(System.Configuration.SettingsContext context, System.Configuration.SettingsPropertyValueCollection collection)
{
string username = context["UserName"].ToString();
string applicationName = (null != context["ApplicationName"] ? context["ApplicationName"].ToString() : String.Empty);
bool isAnonymous = bool.Parse(context["IsAuthenticated"].ToString());
bool isNewProfile = false;
lock (m_profiles)
{
SessionProfile profile = m_profiles.Find(x => (x.Username == username)
&& (x.IsAnonymous == isAnonymous)
&& (x.ApplicationName == applicationName)
);
if (profile == null)
{
profile = new SessionProfile();
profile.Username = username;
profile.ApplicationName = applicationName;
profile.IsAnonymous = isAnonymous;
isNewProfile = true;
}
foreach (SettingsPropertyValue prop in collection)
{
SessionProfileData profileProperty = profile.Properties.Find(x => x.PropertyName == prop.Name);
if (profileProperty != null)
{
profileProperty.PropertyValue = prop.PropertyValue;
}
else
{
profileProperty = new SessionProfileData();
profileProperty.PropertyValue = prop.PropertyValue;
profileProperty.PropertyName = prop.Name;
profile.Properties.Add(profileProperty);
}
}
if (isNewProfile)
m_profiles.Add(profile);
}
}
In the SetPropertyValues method we iterate again over the list of available properties, setting their values.
That is all the coding we need, now it is time to define which properties we want to use in the web.config file:
<!—This sets the custom profile provider –>
<anonymousIdentification enabled=”true”/>
<profile defaultProvider=”SessionProvider”>
<providers>
<add name=”SessionProvider” type=”SessionProfileProvider”/>
</providers>
<properties>
<add name=”FavoriteColor” allowAnonymous=”true” type=”System.String”/>
<add name=”FavoriteName” allowAnonymous=”true” type=”System.String”/>
<add name=”UserInfo” allowAnonymous=”true” type=”PersonalData”/>
</properties>
</profile>
What we are doing in this XML section is:
1. Use our new Profile provider as the default ASP.NET Profile provider.
2. We add support for anonymous users
3. We define which properties can be used and its types, (Did you notice that we can even use custom classes like a “PersonalData” class:
public class PersonalData
{
public PersonalData()
{
}
public string Firstname { get; set; }
public string Lastname { get; set; }
}
Now build your Web Site and create a new page, you will be able to get and set the values of your properties using the Profile class, you can add more properties to your web.config file and all you need is to build the Web Site again:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Profile.FavoriteColor = “Red”;
Response.Write(Profile.FavoriteColor);
}
}
I hope you have found this post interesting and useful, thanks for reading!. You can download the sample project here.
Hi Cesar
Thank you for this great article.
A few typos/suggestions in case it helps:
Steve, London UK
——————-
The SessionProfile class represens each individual session
The SessionProfile class represents each individual session
Now is time to build our custom Profile provider
Now it is time to build our custom Profile provider
lets create the
let’s create the
lets check the two
let’s check the two
is returned with the properties and its values.
is returned with the properties and values.
we obtain the corresponding match in the “m_model” object
?
now is time to define
now it is time to define
Now lets check the other method
Now let’s check the other method
read and write data shared accros a
read and write data shared across a
You can dowload the sample project here.
You can download the sample project here.
Thank you Steve, I’ll be more careful next time, English is not my first language
.