How to use ASP.NET 2.0 Profile object from web service code

You have started to use ASP.NET 2.0 Profile Provider and you are
very happy with it. All your .aspx pages are full of
“Profile.Something”. You also introduced a lot of new properties on
the profile object via web.config. Then you added a new web
service. There you want to access the Profile object. You realize,
you are doomed.

You cannot access the Profile object from Web Service.

At runtime, ASP.NET generates a class looking at the
specification provided in web.config, which becomes the “Profile”
object in .aspx pages. But this object is not available in Web
service (.asmx.cs) and you cannot see the custom properties you
have added in the profile object. Although
HttpContext.Current.Profile will give you reference to Profile
object, but it’s type is ProfileBase which does not show your
custom properties. Makes sense, because the class is generated at
runtime. But if it can be made available in .aspx.cs, then it
should also be available in .asmx.cs.

In order to overcome this problem, you have to hand code that
profile class in your App_Code folder and then configure web.config
so that it does not auto generate the class instead use your one.
Here’s what you do in web.config:

I have added a new attribute UserProfile. Now go to App_Code and
make a UserProfile class like this:

public class UserProfile :
System.Web.Profile.ProfileBase
{
[SettingsAllowAnonymousAttribute(true)]
public virtual int Timezone
{
get
{
return ((int)(this.GetPropertyValue(“Timezone”)));
}
set
{
this.SetPropertyValue(“Timezone”, value);
}

}

Declare all the properties like this. Don’t forget to add the
[SettingsAllowAnonymousAttribute(true)] on the properties which you
want to be made available to anonymous users.

At the end of the class, add this method:

public virtual ProfileCommon
GetProfile(string username)
{
return ((ProfileCommon)(ProfileBase.Create(username)));

}

Here’s an easy way to avoid hand coding this class and
generating it automatically. Before you make the changes in
web.config and create the UserProfile class, run your web project
as it was before. But before running it, turn off SQL Server. This
will make Asp.net execution to break on first call to some Profile
object’s property. For ex, if you have a custom property TimeZone
in the Profile object, execution will break on this line:

public virtual int
Timezone
{
get
{

return
((int)(this.GetPropertyValue(“Timezone”)));

It will fail to load the profile object values from database
because database is down. If you scroll up, you will see this is
the class that ASP.NET generates at run time. You will see all the
properties are declared on this class already. So, you can just
copy & paste it in your own class easily!

But after copying, you will realize there’s no
[SettingsAllowAnonymousAttribute(true)] attribute. So, you will
have to put them manually. Also after making your own custom class,
you will have to remove all the custom properties declared inside node in the web.config.

Now that you have your own Profile class, inside web service,
you can cast (HttpContext.Current.Profile as UserProfile) and then
you can use all the custom properties.

If you don’t want to enjoy strongly typed coding on web service,
then you can always use the old way of accessing Profile properties
via: Profile.GetPropertyValue(“TimeZone”). But it’s no fun.

20 thoughts on “How to use ASP.NET 2.0 Profile object from web service code”

  1. We have an existing Authentication Service, which drops an “AUTH” cookie once user is authenticated. And I want to use this cookie to identify if an user is anonymous or authenticated. I did not find any way to add this information (username and the IsAuthenticated flag) into the Profile SettingsContext.

    Is there a way to do it ?

  2. Excellent article, and nice feedback – all very helpful. I have a challenge to throw out to the group here – I need to actually get a reference to a user and profile (and use these methods as a foundation) BUT I am actually doing this processing from a SQL Server Integration Services package (Script Component) that doesn’t even have a HTTPContext to hook into 🙂

    This is a text file upload of users into my web application.

    Anyone have any thoughts on a way to tackle this? I am *this* close.. but can’t see the way…

  3. You will have to parse content of aspnet_profile row for the user from Script component.

  4. There is another way to avoid hand-coding the custom profile class, without having to run your application with breakpoints or disable the database, as long as you’re using Visual Studio (like me :). In a page that uses your profile, or defines a variable of type ProfileCommon, just right-click on the “ProfileCommon” type identifier and select “Go To Definition.” As long as your site is compiled, the IDE should open up a page like App_Code/profile.abcde123.cs.

    Also, to answer Shamim’s question, a ProfileGroup has to be implemented as a separate class in the file that inherits from ProfileGroupBase. The ProfileGroupBase contains the get & set properties, and then the ProfileBase contains a get method for the group, like so:

    public class MyProfileGroup : System.Web.Profile.ProfileGroupBase {

    public virtual object GroupProperty1 {

    get {

    return ((object)(this.GetPropertyValue(“GroupProperty1”)));

    }

    set {

    this.SetPropertyValue(“GroupProperty1”, value);

    }

    }

    public virtual object GroupProperty2{

    get {

    return ((object)(this.GetPropertyValue(“GroupProperty2”)));

    }

    set {

    this.SetPropertyValue(“GroupProperty2”, value);

    }

    }

    }

    public class MyProfileCommon : System.Web.Profile.ProfileBase {

    public virtual MyProfileGroup MyGroup {

    get {

    return ((MyProfileGroup)(this.GetProfileGroup(“MyGroup”)));

    }

    }

    public virtual MyProfileCommon GetProfile(string username) {

    return ((MyProfileCommon)(ProfileBase.Create(username)));

    }

    }

  5. “Also after making your own custom class, you will have to remove all the custom properties declared inside node in the web.config.”

    In which web.config? The one in the web service or the one in the client using the web service?

    Thanks

    Vida

  6. How would i architect a 3-Tier application that is physically located on different servers. So I want the Profile object in my presentation layer, but that will not work since I can not call the database directly. I need to create a Profile object on the web services layer that can call the database. I am having a hard time trying to figure this out. Can anyone help on this? Every example i see always uses 3 layer that sits on one physical server???

  7. Very good question. I have always struggled with ASP.NET Membership and Provider having a 2-tier model. The solution is to build your own custom provider which uses your standard business layer on middle tier.

    Here’s how to make custom providers:

    msdn2.microsoft.com/…/0580x1f5.aspx

    You can also learn from ASP.NET default membership provider source code:

    weblogs.asp.net/…/442772.aspx

  8. My problem was quite similar to that of the first paragraph, except that I wanted to use my Profile in a normal class library. I’m not sure if this is relevent to webservices too, but I’m just placing the solution here, incase someone else needs it too:

    System.Web.HttpContext.Current.Profile

  9. All discussion is very good. I am facing a problem regarding the implementation of the Custom Profiler.

    I created a OracleProfileProvider: ProfileProvider in a web project app(not a web site), overrides all required functions and properties (ApplicationName, Initialize, GetPropertyValues, SetPropertyValues, DeleteInactiveProfiles, DeleteProfiles, FindInactiveProfilesByUserName, FindProfilesByUserName, GetAllInactiveProfiles, GetAllProfiles, GetNumberOfInactiveProfiles) and also create a class for the properties of the User (UserProfile: ProfileBase). Both of these classes are defined in a namespace (abc.def). I insert the following tags in the web.config

    I didn't find the Profile property in aspx page, After reading this article, I declared a Profile object (protected abc.def.UserProfile Profile = System.Web.HttpContext.Current.Profile as abc.def.UserProfile;) in MyPage class which is inherited from the System.Web.UI.Page, and When I tried to access the Profile object in the aspx page (inherited from MyPage) I got that Profile object has null value. Please tell me what's is wrong in it or what I have to do to overcome this problem.

    Thanks a lot.

  10. I am having an issue with attempting to use Profile groups in my custom user profile object. When I attempt to access a property from the group, I get the following exception:

    System.Configuration.Provider.ProviderException was unhandled by user code

    Message=”The profile group 'Preferences' has not been defined.”

    Source=”System.Web”

    StackTrace:

    at System.Web.Profile.ProfileBase.GetProfileGroup(String groupName)

    at TODv2.Core.Profile.TODUserProfile.get_Preferences() in C:ProgrammingProjects2008TODv2TODv2.CoreProfileTODUserProfile.cs:line 40

    at TODv2.Core.Base.BasePage.OnPreInit(EventArgs e) in C:ProgrammingProjects2008TODv2TODv2.CoreBaseBasePage.cs:line 75

    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

    I have scoured Google, but there doesn't seem to be much information on this configuration. Or I need to brush up on my Googling skills.

    Can anyone point out what I'm missing? Below is the code for the profile group and profile itself.

    Thanks!

    public class TODUserProfilePreferencesGroup : ProfileGroupBase {

    [SettingsAllowAnonymous(false)]

    public virtual string Theme {

    get { return (string)this.GetPropertyValue(“Theme”); }

    set { this.SetPropertyValue(“Theme”, value); }

    }

    [SettingsAllowAnonymous(false)]

    public virtual int Timezone {

    get { return (int)this.GetPropertyValue(“Timezone”); }

    set { this.SetPropertyValue(“Timezone”, value); }

    }

    }

    public class TODUserProfile : ProfileBase {

    public virtual TODUserProfilePreferencesGroup Preferences {

    get { return (TODUserProfilePreferencesGroup)(this.GetProfileGroup(“Preferences”)); }

    }

    public virtual TODUserProfile GetProfile(string username) {

    return (TODUserProfile)ProfileBase.Create(username);

    }

    }

  11. Hi,

    If I run my application from IIS the why HttpContext.Current.Profile value is null. If I run from IDE the value is not null. Is it the problem with IIS or SQl Server. SQLExpress is running on my machine. Please let me know the problem. Thanks in advance.

  12. I'm having the same problem on groups. My definition of the group looks like this:

    Public Class CG_ProfGrpWorkPhone : Inherits System.Web.Profile.ProfileGroupBase

    ' Defines business object layer component for the WorkPhone number

    Public Overridable Property CountryCode() As String

    Get

    Return CType(Me.GetPropertyValue(“CountryCode”), String)

    End Get

    Set(ByVal value As String)

    Me.SetPropertyValue(“CountryCode”, value)

    End Set

    End Property

    Public Overridable Property AreaCode() As String

    Get

    Return CType(Me.GetPropertyValue(“AreaCode”), String)

    End Get

    Set(ByVal value As String)

    Me.SetPropertyValue(“AreaCode”, value)

    End Set

    End Property

    Public Overridable Property Phone1() As Integer

    Get

    Return CType(Me.GetPropertyValue(“Phone1”), Integer)

    End Get

    Set(ByVal value As Integer)

    Me.SetPropertyValue(“Phone1”, value)

    End Set

    End Property

    Public Overridable Property Phone2() As Integer

    Get

    Return CType(Me.GetPropertyValue(“Phone2”), Integer)

    End Get

    Set(ByVal value As Integer)

    Me.SetPropertyValue(“Phone2”, value)

    End Set

    End Property

    End Class

    … and my attempt to include this group in my custom profile object looks like this:

    Public Overridable ReadOnly Property WorkPhone() As CG_ProfGrpWorkPhone

    Get

    Return CType(Me.GetProfileGroup(“WorkPhone”), CG_ProfGrpWorkPhone)

    End Get

    End Property

    Whenever I run this, I get the error message:

    The profile group 'WorkPhone' has not been defined.

    When I run it in the debugger right before I hit the exception, I see that all of my non-group properties are returning values but the group property has an error System.Web.Profile.ProfileBase.GetProfileGroup(String groupName).

    So it look like ASP.NET is ignoring my group class definition. Is there some trick in web.config to tell it to pay attention to that class. I played around with the “inherits” key word in the tag, but that didn't work.

  13. Jim – not just Galloway, and Omar here, but also K Scott Allen:

    odetocode.com/…/2653.aspx [comments blocked]

    I use profile groups for stuff that is specific to membership role. I understand that “multiple profiles based on role” is ILLEGAL in ASP.NET, but we can use groups for this encapsulation. I ended up doing away with my custom groups and going back to web.config just for these groups.

    But I also have role-specific static members (to fill in ObjectDataSource and the like). Since I can no longer rely on my own profile grouping classes, I created a new class inheriting from ProfileCommon for these static members.

    I would much rather have stuck them in the same class as the profile groups.