Getting Strongly Typed Profile Properties From a Class Library
Separating your application layers into class libraries offers several advantages, but one of the disadvantages is that you lose access to ASP.NET's dynamically-compiled ProfileCommon class, which provides strong-typing for profile properties. Here's how to regain the advantage of strongly typed profile properties in a class library.
(EDIT: If you're looking for a similar example dealing with accessing profiles in web application projects, don't forget to check out this post as well.)
Profiles offer a much more reliable alternative to cookies or Session state for storing user information. Unlike cookies or Session state, profile properties are strongly typed, meaning that their types are known at design time. This lets us access them without casting, do compile-time checking on them, use Intellisense with them, and so on.
As you'll recall, profile properties are defined in web.config file as follows:
<profile>
<properties>
<add name="FirstName" />
<add name="LastName" />
<add name="DateOfBirth" type="System.DateTime" />
properties>
profile>
This is a pretty simple profile - just three properties, two String and one DateTime. Let's take a look at how we can refer to these properties from our code.
Strongly Typed Profile from the Page
Accessing strongly typed profile properties from the page is pretty easy - in fact, it's totally transparent in ASP.NET, requiring no explicit configuration whatsoever. This happens thanks to a bit of clever sleight-of-hand ASP.NET performs behind the scenes.
When you define a profile, ASP.NET dynamically creates a class called ProfileCommon which inherits from System.Web.Profile.ProfileBase. Here is the actual ProfileCommon class that is compiled from the profile defined in the example above.
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:2.0.50727.3053
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
using System;
using System.Web;
using System.Web.Profile;
public class ProfileCommon : System.Web.Profile.ProfileBase {
public virtual System.DateTime DateOfBirth {
get {
return ((System.DateTime)(this.GetPropertyValue("DateOfBirth")));
}
set {
this.SetPropertyValue("DateOfBirth", value);
}
}
public virtual string LastName {
get {
return ((string)(this.GetPropertyValue("LastName")));
}
set {
this.SetPropertyValue("LastName", value);
}
}
public virtual string FirstName {
get {
return ((string)(this.GetPropertyValue("FirstName")));
}
set {
this.SetPropertyValue("FirstName", value);
}
}
public virtual ProfileCommon GetProfile(string username) {
return ((ProfileCommon)(ProfileBase.Create(username)));
}
}
ProfileBase provides untyped access to profile properties through its GetPropertyValue and SetPropertyValue methods. As you can see above, ProfileCommon inherits this class, and casts the untyped values to the types defined in web.config before returning them.
When the application runs, ASP.NET populates the Page.Profile property with an instance of this ProfileCommon class. This lets us read and modify the profile's properties in a strongly-typed way through the page's Profile property:
using System;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
lblGreeting.Text =
"Hello, " + Profile.FirstName + " " + Profile.LastName +
". Your DOB is " + Profile.DateOfBirth.ToShortDateString() + ".";
}
}
As I said, you don't have to do anything to make this work -- the runtime takes care of it all for us. So far, so good.
Strongly Typed Profile from a Class
Now, let's say we have a custom class in App_Code from which we want to access profile properties.
Obviously, our class won't have an automatically-populated Profile property like the Page class does. But fortunately, we do still have access to the ProfileCommon class, which means we can create our own Profile property.
using System.Web;
public class ProfileInfo
{
private static ProfileCommon Profile
{
get { return (ProfileCommon)HttpContext.Current.Profile; }
}
public static string GetFullName()
{
return Profile.FirstName + " " + Profile.LastName;
}
public static string GetDateOfBirth()
{
return Profile.DateOfBirth.ToShortDateString();
}
}
As you can see, to create a strongly-typed Profile for use in a class, all we need to do is to get a reference to the Profile property of the current HttpContext, which is of type ProfileBase. Then, we can cast it to type ProfileCommon to get the strong typing. From there, we can use our created Profile property in any way we choose. To illustrate this, I've created a couple of methods that use it.
The following code shows how we can call this App_Code class from a page:
using System;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
lblGreeting.Text =
"Hello, " + ProfileInfo.GetFullName() +
". Your DOB is " + ProfileInfo.GetDateOfBirth() + ".";
}
}
Strongly Typed Profile from a Class Library
Now, what if we now want to move this class from App_Code out to a class library?
You'll find that if you do this, you'll encounter the following build error:
The type or namespace name 'ProfileCommon' could not be found (are you missing a using directive or an assembly reference?)
Bummer. As you can see, the ProfileCommon class isn't accessible from an outside class library. What to do?
One option is to use the Profile object from the current HttpContext directly. This will work, but unfortunately we lose the benefits of strong typing. As you'll recall, HttpContext.Profile is of type ProfileBase, which provides only untyped access to profile information.
using System;
using System.Web;
using System.Web.Profile;
namespace BLL
{
public class ProfileInfo
{
private static ProfileBase Profile
{
get { return HttpContext.Current.Profile; }
}
public static string GetFullName()
{
return (string)Profile.GetPropertyValue("FirstName") +
" " +
(string)Profile.GetPropertyValue("LastName");
}
public static string GetDateOfBirth()
{
return ((DateTime)Profile.GetPropertyValue("DateOfBirth")).ToShortDateString();
}
}
}
However, there is another option that will allow us to access a strongly typed Profile from a class library.
To do that, we need to define a new class in the library that contains the properties we want in our profile. This class must inherit ProfileBase. Let's call our class CustomProfile:
using System;
namespace BLL
{
public class CustomProfile : System.Web.Profile.ProfileBase
{
private string _firstName = "First Name";
private string _lastName = "Last Name";
private DateTime _dateOfBirth = DateTime.MinValue;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
public DateTime DateOfBirth
{
get { return _dateOfBirth; }
set { _dateOfBirth = value; }
}
}
}
Then in web.config, instead of defining the properties directly, we'll inherit this new class in the
<profile inherits="BLL.CustomProfile" />
Now, we can use this type to define a Profile from any class in the library. This Profile will be of the type we just created and inherited in web.config:
using System.Web;
namespace BLL
{
public class ProfileInfo
{
private static CustomProfile Profile
{
get { return (CustomProfile)HttpContext.Current.Profile; }
}
public static string GetFullName()
{
return Profile.FirstName + " " + Profile.LastName;
}
public static string GetDateOfBirth()
{
return Profile.DateOfBirth.ToShortDateString();
}
}
}
Hey, it looks like we've got our strong typing back! If you think about it, this is somewhat akin to "rolling our own" ProfileCommon class.
Here's how we could now call our library class from a page:
using System;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
lblGreeting.Text =
"Hello, " + BLL.ProfileInfo.GetFullName() +
". Your DOB is " + BLL.ProfileInfo.GetDateOfBirth() + ".";
}
}
As you can see, it's possible to access a strongly-typed Profile object from anywhere you need to in ASP.NET - from the page, from a dynamically-compiled class in App_Code, and yes, even from a class library. Enjoy!
Subscribe to this blog for more cool content like this!
You've been kicked (a good thing) - Trackback from DotNetKicks.com
Pingback from ASP.NET Profiles in Web Application Projects : LeeDumond.com