Writing a custom ASP.NET Profile class
We made heavy use of the ASP.NET membership and profile system for Video.Show (a Silverlight 1.0 video community website system, available on CodePlex). In addition to storing basic profile information, we created a custom profile with some additional fields. It's a really easy way to add add some additional personalization to your site without having to add a bunch of tables to your database.
This is really simple if you're using a Website Project - you can just add additional properties to the profile section of your web.config, and a custom profile class is generated on the fly when you rebuild your application. That makes things ridiculously easy. First, we'd define the property in web.config:
<!-- In web.config --> <profile > <properties> <add name="FavoritePasta" /> </properties> </profile>
Profile.FavoritePasta = "Pumpkin Ravioli";
<span id="user-favorite-pasta"><%= Profile.FavoritePasta %></span>
Not so fast, I'm using a Web Application Project
Yeah, here's the catch. If you're using the Web Application Project model, the custom build handling for the profile doesn't kick in, so those custom properties you've lovingly crafted in your web.config aren't going to be compiled into a custom profile class.
There's a Visual Studio 2005 add-in called WebProfile that reads your custom profile and creates a custom class for you. That's handy, but I passed on it. For one thing, I haven't heard that there's a VS 2008 version of this. Additionally, I don't like to require a custom add-in in order to get my code to work in case I want to add a new profile property - especially when I'm working on a project that's going to be distributed on CodePlex.
Fortunately, it's not very hard to implement a custom profile. First, we'll write a class that inherits from System.Web.Profile.ProfileBase. I added a few static accessors, too:
using System.Web.Profile; using System.Web.Security; namespace VideoShow { public class UserProfile : ProfileBase { public static UserProfile GetUserProfile(string username) { return Create(username) as UserProfile; }public static UserProfile GetUserProfile() { return Create(Membership.GetUser().UserName) as UserProfile; } [SettingsAllowAnonymous(false)] public string Description { get { return base["Description"] as string; } set { base["Description"] = value; } } [SettingsAllowAnonymous(false)] public string Location { get { return base["Location"] as string; } set { base["Location"] = value; } } [SettingsAllowAnonymous(false)] public string FavoriteMovie { get { return base["FavoriteMovie"] as string; } set { base["FavoriteMovie"] = value; } } } }
<profile inherits="VideoShow.UserProfile"> <providers> <clear /> <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="VideoShowConnectionString"/> </providers> </profile>
//Write to a user profile from a textbox value
UserProfile profile = UserProfile.GetUserProfile(currentUser.UserName);
profile.FavoriteMovie = FavoriteMovie.Text;
profile.Save();
Part of the reason for the accessor is to allow display of profile information for users other than the current user - for instance, a public profile page which displays information about other users in the system.
//Write to a user profile from a textbox value
UserProfile profile = UserProfile.GetUserProfile(displayUser.UserName);
Response.Write(profile.FavoriteMovie)
And of course, I can still databind to it as well:
<span id="user-favorite-movie"><%= VideoShow.UserProfile.GetUserProfile().FavoriteMovie %></span>
A few disclaimers:
- This isn't news, it's been out since ASP.NET 2.0 shipped. Still, it's pretty handy to know about, and if you're like me you may have forgotten or never really dug into some of the ASP.NET 2.0 goodies.
- This isn't the ultimate solution in terms of entity modeling. Custom profile information is stored in two columns in the aspnet_Profile table (delimited strings in one column, another column for binary serialized objects). That means that the only real way to read or write custom property values is via the profile API. That's not a real problem unless you need to query or join on information stored in a custom profile setting.
Further information:
Profiles in ASP.NET (K. Scott Allen)
Essential ASP.NET 2.0, Chapter 5 (Fritz Onion)