My musings about .NET and what not

ASP.NET Profiles in Web Application Projects

Accessing ASP.NET profiles from a web application project is remarkably easy once you know how. Here’s how it’s done, along with a fully working implementation that you can download.


Earlier this year, I blogged about how to create a strongly-typed Profile that could be accessed from a class library. In response to popular demand, today I’m presenting a similar (but more substantial) example geared specifically toward accessing profiles in web application projects.

There are plenty of blog posts that talk about this, but unfortunately very few that show how to do it. Most of them instead refer to this relatively obscure add-in for Visual Studio 2005 (apparently. you’re out of luck if you’re using Visual Studio 2008). However, the good news is you don’t need a third party add-in or build task for this, as implementing this functionality yourself is not difficult at all.

If you’re reading this, I’ll assume you’re aware of the differences between an ASP.NET web site and a web application, so I won’t go into the various differences in great detail (feel free to consult the MSDN for more information). For our purposes, it’s just important to understand that in a web application project, there is no ProfileCommon class or Page.Profile property to work with, as we’re accustomed to seeing in web site projects – hence the problem.

Web site projects accomplish this bit of magic through dynamic compilation – essentially creating the needed objects at runtime, “on the fly” as it were. In effect we will be doing the exact same thing, but the old-fashioned way – with a simple hand-written proxy class.

Writing a Profile Proxy Class

Let’s assume for the sake of discussion that we have several bits of user information we want to store in profile.

  • first name
  • last name
  • date of birth
  • gender
  • the user’s time zone
  • the user’s preferred culture

Now, we could store these as separate value types, but in practice I find it easier to group related properties together in a class. So let’s create a class Personal to store the first four properties, and a class Preferences to store the time zone and culture. Make sure to decorate these classes with the [Serializable] attribute.

namespace LD.Sample.BLL
{
   using System;

   [Serializable]
   public class Personal
   {
      public string FirstName { get; set; }

      public string LastName { get; set; }

      public DateTime DateOfBirth { get; set; }

      public Gender Gender { get; set; }
   }
}
namespace LD.Sample.BLL
{
   using System;

   [Serializable]
   public class Preferences
   {
      public string TimeZone { get; set; }
      
      public string Culture { get; set; }
   }
}

Next, we’ll write a class that will define the profile we want, incorporating the two custom types shown above as properties. This class will inherit ProfileBase . Let’s call it CustomProfile.

namespace LD.Sample.BLL
{
   using System.Web;
   using System.Web.Profile;

   public class CustomProfile : ProfileBase
   {
      public Personal Personal
      {
         get { return (Personal) GetPropertyValue("Personal"); }
      }

      public Preferences Preferences
      {
         get { return (Preferences) GetPropertyValue("Preferences"); }
      }

      /// 
      /// Get the profile of the currently logged-on user.
      ///       
      public static CustomProfile GetProfile()
      {
         return (CustomProfile) HttpContext.Current.Profile;
      }

      /// 
      /// Gets the profile of a specific user.
      /// 
      /// The user name of the user whose profile you want to retrieve.
      public static CustomProfile GetProfile(string userName)
      {
         return (CustomProfile) Create(userName);
      }
   }
}

Note that I’ve also included two overloaded static GetProfile methods. GetProfile()  lets us obtain the profile of the current user, while GetProfile(string userName) lets us get the profile of a specific user (for administrative purposes, or when creating a new member, for example).

One more thing – and this is very important – we need to define the provider in web.config.



   

You’ll see that our provider is of type System.Web.Profile.SqlProfileProvider. Of course, this assumes that the database to which this is pointing has been configured with the schema required to support SqlProfileProvider.

Also note the inherits attribute in . This is what tells the provider where to obtain the profile properties – in our case, from the CustomProfile class. When you do this, you do not want to define the properties declaratively in web.config, as you would in a website project. If you do, you’ll get a System.Configuration.ConfigurationException, informing you that the profile property has already been defined.

Usage

And that, believe it or not, is all there is to setting up a strongly-typed profile for use in a web application project. Now, let’s take a look at how you can use this newly-implemented goodness.

Here is some code that shows setting profile values for the currently logged-on user.

CustomProfile profile = CustomProfile.GetProfile();

profile.Personal.FirstName = "Tami";
profile.Personal.LastName = "Gharst";
profile.Personal.DateOfBirth = new DateTime(1972, 7, 10);
profile.Personal.Gender = Gender.Female;
profile.Preferences.TimeZone = "W. Europe Standard Time";
profile.Preferences.Culture = "de-DE";

profile.Save();

Here is some code that shows setting profile values for a specific user with the user name “Lee”.

CustomProfile profile = CustomProfile.GetProfile("Lee");

profile.Personal.FirstName = "Lee";
profile.Personal.LastName = "Dumond";
profile.Personal.DateOfBirth = new DateTime(1961, 10, 9);
profile.Personal.Gender = Gender.Male;
profile.Preferences.TimeZone = "Central Standard Time";
profile.Preferences.Culture = "en-US";

profile.Save();

If you like, you can make this even simpler by adding a Profile property to the page you’re working with – or even better, inherit your pages from a base type and add it there, so it’s available to all of your pages. This lets you set and retrieve profile properties with the familiar ASP.NET web site syntax.

// set profile properties

Profile.Personal.FirstName = "Lee";
Profile.Personal.LastName = "Dumond";
Profile.Personal.DateOfBirth = new DateTime(1961, 10, 9);
Profile.Personal.Gender = Gender.Male;
Profile.Preferences.TimeZone = "Central Standard Time";
Profile.Preferences.Culture = "en-US";

Profile.Save();
// display profile properties

lblDisplay.Text =
   string.Format(
      "User {0} had a real name of {1} {2}, was born on {3}, lives in the {4} time zone, and has a preferred culture of {5}.",
      Profile.UserName, 
      Profile.Personal.FirstName, 
      Profile.Personal.LastName,
      Profile.Personal.DateOfBirth.ToShortDateString(),
      Profile.Preferences.TimeZone,
      Profile.Preferences.Culture);

Sample Application

As I mentioned, I’ve included a downloadable web application solution that demonstrates web application profiles in action. When you run it, you’ll be greeted by the following screen:

image

There are screens that let you display a profile, edit a profile, and create a new one.

image

image

Examining the source code, along with the preceding explanation, should make understanding these concepts a snap.

I hope this helps the next time you find yourself needing access to profile properties from a web application!

Download sample code: WebApplicationProfileSample.zip

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. Getting Strongly Typed Profile Properties From a Class Library
    2. Building a TweetThis Extension with Automatic Bit.ly for Graffiti CMS
    3. Singletons vs. Static Classes

    » Trackbacks & Pingbacks

    1. Pingback from Getting Strongly Typed Profile Properties From a Class Library : LeeDumond.com

    2. Pingback from Twitter Trackbacks for ASP.NET Profiles in Web Application Projects : LeeDumond.com [leedumond.com] on Topsy.com

      Twitter Trackbacks for ASP.NET Profiles in Web Application Projects : LeeDumond.com [leedumond.com] on Topsy.com — October 8, 2009 9:42 AM
    3. You've been kicked (a good thing) - Trackback from DotNetKicks.com

      ASP.NET Profiles in Web Application Projects — October 8, 2009 10:19 AM
    4. DotNetBurner - burning hot .net content

      ASP.NET Profiles in Web Application Projects — October 8, 2009 6:42 PM
    5. Pingback from ASP.NET Profiles in Web Application Projects : LeeDumond.com | Webmaster Tools

      ASP.NET Profiles in Web Application Projects : LeeDumond.com | Webmaster Tools — October 8, 2009 6:55 PM
    6. Pingback from Dew Drop – October 9, 2009 | Alvin Ashcraft's Morning Dew

      Dew Drop – October 9, 2009 | Alvin Ashcraft's Morning Dew — October 9, 2009 8:21 AM
    7. Daily tech links for .net and related technologies - October 9-11, 2009 Web Development Using MvcContrib

      Daily tech links for .net and related technologies - October 9-11, 2009 — October 10, 2009 3:16 AM
    8. Thank you for submitting this cool story - Trackback from DotNetShoutout

      ASP.NET Profiles in Web Application Projects — October 15, 2009 6:32 AM
    9. You are voted (great) - Trackback from WebDevVote.com

      ASP.NET Profiles in Web Application Projects — October 15, 2009 6:34 AM
    Trackback link for this post:
    http://leedumond.com/trackback.ashx?id=78

    » Comments

    1. Anthony avatar

      Cool explanation! Joel Wrobel has taken the project you mention on CodePlex and updated it to work as a build task that is supposed to work for VS 2008 - I haven't tried it. But it does allow use of the config file for the declarations:

      weblogs.asp.net/.../web-profile-bui

      I still prefer your way because it is self-documenting! :-)

      Anthony — October 8, 2009 10:01 AM
    2. Steve Walker avatar

      Yup; I've found when migrating from web to app it was always a bind to re-do all the profile stuff but after a good dig about I found two ways:

      a get:

      decimal delivery = (decimal)Context.Profile.GetPropertyValue("delivery");

      a set:

      Context.Profile.SetPropertyValue("delivery", delivery);

      Work perfectly well, you have to cast the profile object but that is not a major headache if you're only using it here and there - and sometimes quicker than a class, but less portable.

      The other option is the custom build provider for WebProfile which works very well. Add that to VS2008 or earlier and then just let it run once and a class is created for your profile from the details in the web.config, drop that in your code folder and you're good to go!

      It's up on codeplex and even has a config file for making changes to the classname, filename and location of the generated code. http://webprofile.codeplex.com - In fact once you've made the class and you're not changing it then you can out the build task and only re enable it when you need to update the profile class if you've changed it.

      Regards,

      Steve

      Steve Walker — October 23, 2009 5:30 AM
    3. Maxi avatar

      However, the good news is you don’t need a third party add-in or build task for this

      Agree X 100

      Maxi — December 23, 2009 8:14 PM
    4. Maxi avatar

      Have you try to put that profile.cs in App_Code.

      It will give you casting error, how is that?

      Maxi — December 23, 2009 9:22 PM
    5. Lee Dumond avatar

      @Maxi - This applies to Web Application Projects only. There is no App_Code, as you can see from the sample download.

      Lee Dumond — December 23, 2009 9:32 PM
    6. Phil avatar

      Thanks for the examples - they've really helped tidy up my profile coding. I do have one question though (and I can't seem to find the answers anywhere else). I want to use profiles for anonymous web users and for some reason if I add a "CreateAnon" method to the custom class I can't get the class' "Save" method to then work unless I specify that the user is authenticated within CreateAnon. For example:

      public static CustomProfile GetProfileAnon()

      {

      return (CustomProfile)Create(HttpContext.Current.Request.AnonymousID, true);

      }

      If I specify false as the second param I get a CustomProfile object OK but the values just don't save when I call the Save event (no SQL row is added to the "Users" table, etc). FYI I've already added the following directive to the web.config:

      Strangely I don't get an exception when saving the CustomProfile object, it's just that it doesn't save.

      Any ideas would be appreciated... :-)

      Phil — February 23, 2010 10:14 AM
    7. Andy Nelms avatar

      Thank you Lee for an excellent example.

      Andy Nelms — March 2, 2010 12:17 PM
    8. Neil avatar

      Marvellous stuff - have been searching around for ages and this is the first site I've found that concisely explains an easy way to use the Profile object.

      I'm still a little mystified as to WHY the Profile is a pain by default in Web Apps, but... ours is not to question why I suppose.

      Thanks again :)

      Neil — May 11, 2010 5:09 PM
    9. Erik avatar

      Great article Lee. Thanks for taking the time to write and post it. Now that I have a better understanding, I'm trying to adapt your method to work with a SQL stored procedure profile provider in VS 2010 and .net 4. My stored procedure profile provider wants look in the web.config properties section for the properties collection. It seems that somehow I need to re-point the functions looking for the props in the web.config to the new definition location which is a class similar to the ones defined in your example.

      The signature of the sub is:

      Private Sub GetProfileDataFromSproc(ByVal properties As SettingsPropertyCollection, ByVal svc As SettingsPropertyValueCollection, ByVal username As String, ...) where the SettingsPropertyCollection is the collection it wants to grab in the web.config properties section. Any ideas how to get this to reference the new defintions in the custom profile classes?

      Erik — June 19, 2010 3:00 PM
    10. tom avatar

      Hi,

      Do you know if this can be used with the SqlTableProfileProvider?

      thanks,

      tom

      tom — August 17, 2010 10:54 PM
    11. Lee Dumond avatar

      @tom: I don't see why it wouldn't.

      Lee Dumond — August 19, 2010 2:10 PM
    12. jkade avatar

      The reason it can't be out of the box is that, by default, the SqlTableProfileProvider looks at the properties config section for configuration about the DB columns.

      The "best" way to get around this is probably to define attributes that supply the missing data (default value, column name, DB type) and mark the properties with them, then modify the SqlTableProfileProvider to reflect over the custom profile class.

      Of course, there are a lot of less best-practicey ways to do it...

      jkade — September 10, 2010 3:42 PM
    13. Zorig avatar

      hi

      as i see this profile method save profile informations as XML in database and it work well.

      i need to know is there any way to change it?

      i need save also som binary like pictures for user.

      thanks

      Zorig — December 18, 2010 3:34 AM
    14. Hi there.. Thanks for this sample... it helped me out, so I figgure I share...

      To run this with the SqlTableProfileProvider you need to declare custom attributes... ie:

      namespace LD.Sample.BLL

      {

      class CustomProfile : ProfileBase

      {

      public static CustomProfile GetProfile()

      {

      return (CustomProfile)HttpContext.Current.Profile;

      }

      public static CustomProfile GetProfile(string userName, bool isAuthenticated)

      {

      return (CustomProfile)Create(userName, isAuthenticated);

      }

      [CustomProviderData("FirstName;nvarchar")]

      public virtual string FirstName

      {

      get

      {

      return ((string)(this.GetPropertyValue("FirstName")));

      }

      set

      {

      this.SetPropertyValue("FirstName", value);

      }

      }

      [CustomProviderData("LastName;nvarchar")]

      public virtual string LastName

      {

      get

      {

      return ((string)(this.GetPropertyValue("LastName")));

      }

      set

      {

      this.SetPropertyValue("LastName", value);

      }

      }

      }

      }

      Henry — January 10, 2011 12:56 PM
    15. Serina Gonsar avatar

      Thanks for great post

      ..

      Serina Gonsar — February 18, 2011 8:53 PM
    16. vuitton bags avatar

      I’m sorry to say there may be a louis vuitton tote bag lie in your closet.And now run to see whether there is a woven label say it’s made in US?Coach,mostly we can say it as a fashion icon,but can’t regard as costless goods.During the worse economic crisis ages,louis vuitton tote CEO Lew Frankfort had a new definition as a young silk-stocking brand “You can own it easily”.We can’t deny the saying run it’s degree up.Let’s take a Lv as an example which you can buy it at around 6000 RMB while a louis vuitton mens wallet tote only deserve one third of it.Though you see all louis vuitton tote selling shops or flagship malls close to LV but it still can’t play as it was that degree.Just like we all know that neighbours have different degrees too.Thanks for the high duties ,discount louis vuitton bags tote becomes valuable brand,but we still confuse a 5000 RMB bag has a what percentage for government?

      vuitton bags — May 7, 2011 12:42 PM

    » Leave a Comment