My musings about .NET and what not

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

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

kick it on DotNetKicks.com

shout it on DotNetShoutOut.com

vote it on WebDevVote.com

Bookmark / Share

    » Similar Posts

    1. How to Prevent Profile Properties From Updating a User's Last Activity Date
    2. ASP.NET Profiles in Web Application Projects
    3. Defensive Programming, or Why Exception Handling Is Like Car Insurance

    » Trackbacks & Pingbacks

    1. You've been kicked (a good thing) - Trackback from DotNetKicks.com

      Getting Strongly Typed Profile Properties From a Class Library — January 15, 2009 10:15 AM
    2. Pingback from ASP.NET Profiles in Web Application Projects : LeeDumond.com

    Trackback link for this post:
    http://leedumond.com/trackback.ashx?id=38

    » Comments

    1. phil avatar

      what an amazing article and so well writen, just the information I was looking for - thanks!

      phil — February 12, 2009 5:28 AM
    2. deon avatar

      You sure know your stuff and you certainly also know how to convey it to mere mortals like myself.

      Thanks a million for this brilliant explanation!!

      deon — February 24, 2009 2:51 PM
    3. Sara avatar

      I think I love you man! You do not know how many problems I was having with this simple, simple thing. I had a class written that I just could not seem to get to work properly. I immediately realized the problem with my code after looking at your code. I have spent hours trying to tweak to get things perfect and then I found you! :-) You have just made this woman's life so much better....all from a few lines of code! Happpppppy Friday to you and me!!!

      Sara — March 13, 2009 8:48 AM
    4. Lee Dumond avatar

      Thanks Sara, glad this article helped you out. That's what I like to hear!

      Lee Dumond — March 13, 2009 9:29 AM
    5. Rachel avatar

      Thanks Lee! I will be studying this. I need to add State (a user's State - i.e., Virginia, etc.) to my profile properties and wasn't sure how to do that. This sounds like what I need.

      Rachel — March 13, 2009 10:29 AM
    6. stg avatar

      Are you sure that this works?

      The CustomProfile class properties won't save or retrieve anything from the ProfileProvider...

      stg — March 19, 2009 8:18 AM
    7. Lee Dumond avatar

      Um, yeah, it works, assuming you have set up your profile provider correctly to begin with. That's not covered here.

      Lee Dumond — March 19, 2009 9:18 AM
    8. Feras avatar

      Man,

      i have been reading alot of blogs and tuts, and i swear to god i can feel your great soul in your writings on your blog, you are such an amazing Pro.

      i recently switched to Web application project and i got shocked that there is no intellisense or direct access to Profile, and your approach totally saved me.

      god bless you and please always bring us new articles and your wisdom.

      Feras — March 21, 2009 9:50 AM
    9. Anthony Yott avatar

      Good article sir. However, you forgot to mention the Profile property does NOT show up magically for a web application project.

      Anthony Yott — May 11, 2009 10:36 AM
    10. Lee Dumond avatar

      @Anthony -- I thought I made it fairly clear that the Page.Profile property is only populated during dynamic compilation. And of course, web application projects are not dynamically compiled.

      Lee Dumond — May 11, 2009 11:14 AM
    11. skhan avatar

      Very well written article.

      How can I do the following in my App_Code class ?

      ProfileCommon profile = this.Profile;

      profile = this.Profile.GetProfile(userName);

      I want to access the First & Last names of the specified user and not the current logged-in user.

      skhan — January 15, 2010 8:06 AM
    12. skhan avatar

      Okay, got it from your another article ! Thank you !

      ProfileCommon profile = (ProfileCommon)ProfileBase.Create(userName);

      string fullUserName = profile.FirstName + " " + profile.LastName;

      skhan — January 15, 2010 8:27 AM
    13. Sonic avatar

      Any ideas how you could modify this to work with property group names?

      Sonic — May 25, 2010 5:26 AM
    14. Sonic avatar

      Got it, you can just create a different custom profilecommon class for each group.

      Sonic — May 25, 2010 5:28 AM

    » Leave a Comment