Jeff and .NET

The .NET musings of Jeff Putz

Sponsors

News

My Sites

ASP.NET Profile sure has some weird quirks

When you read a property from your Profile provider, you'd think that it will only call the provider's GetPropertyValues method, right? Well as it turns out, it's calling the SetPropertyValues as well, on every call. I can't for the life of me figure out why it would do that.

Then, when I was looking a little deeper, I found that the framework will call FindProfilesByUserName whenever you try to hit Profile.LastActivityDate or Profile.LastUpdateDate. The SQL provider does this and it looks for just one record in one page (the method is intended to do paged data calls). So what happens if your provider looks for partial matches, which is kind of the point if you're worried about getting pages of data?

The more I get into this stuff, the more hackish it seems. I think Membership and Profile are great ideas, but the implementation leaves a lot to be desired. 

Posted: Aug 03 2006, 10:51 AM by Jeff | with 10 comment(s)
Filed under:

Comments

Chris D said:

I have to say i am not impressed at all with the stock ProfileProvider.  I would only use it for the most simple of applications.

The fact that it stores it's values in a key/pair string (or serialized form, can't remember) in an ntext column should be enough reason for anybody to ditch it and write their own custom provider.  At the very least they could have provided a sql2k5 option to use an nvarchar(max) and preserve creating profile properties in web.config, but really, using a single column which needs parsing or deserializing every time to get a single property, lame.

# August 3, 2006 12:05 PM

AndrewSeven said:

I agree, my limited experience using it has given me the same hackish feeling.

# August 3, 2006 12:22 PM

PaulWilson said:

Its stuff like this that helped convince me that all I really wanted was my own strongly typed profile class which I load and persist the way I want.  Yes, it does "limit" things by not allowing you to just add a new member in the config file (or even programmatically), but in a real enterprise app that just isn't really going to happen anyhow.  Instead I'm much more concerned with building a scalable and performant application, and I simply want to expose some user properties as part of the built-in profile class.  So my properties are stored in a normalized database table so that they can used and versioned outside of the asp.net profile infrastructure if I see a need.  I also optimize things for my anonymous users by loading and persisting their profile information in cookies -- maybe not something you want to do, but I have that flexibility.

# August 3, 2006 1:29 PM

Jeff said:

Performant is not an adjective, it's a noun. :) Sorry, just one of my pet peeves.

I agree with everything you're saying. However, the reason I wanted to use these API's on my forum project is because the single biggest issue for people who need to integrate is there's no other common API. I'd like to see ASP.NET appeal to more of the audience currently interested only in PHP or Ruby or whatever. I want to put something out there that says, "Hey, you can integrate this into your own site with just some config changes."

Perhaps I should be rolling things my way instead, and have people write a provider through my own API. That wouldn't be my first choice.

# August 3, 2006 1:39 PM

ScottGu said:

I believe it is calling your SetPropertyValues method because you are using a complex type object (and not a primitive type like string, int, etc).  In cases like these the Profile API can't really tell whether the object has changed since there is no standard way to tell with a nested graph of objects like this (although if you wrote an underlying provider you could diff the results with the latest serialized and determine it based on that).

There is a configuration switch in the <profile> section of web.config that allows a developer to turn off the automatic update behavior of Profile:  <profile automaticSaveEnabled="false" />.  If autosave is turned off the developer can use their own logic for dirty detection, and when necessary call Profile.Save().  This avoids you having to build a provider at all and would give you total control over the save semantics.

To answer Chris' question above, the built-in Profile Provider does persist settings as an XML blob as opposed to within a strongly-typed table.  However, you can download this Profile Provider from the web to achieve what you are after instead: http://weblogs.asp.net/scottgu/archive/2006/01/10/435038.aspx  The provider allows you to map the Profile API against either a table directly or against SPROCs (where you could implement your own shredding behavior).

For the second issue, this occurs because the LastActivityDate and LastUpdatedDate are not considered part of the profile data itself.  The profile properties are defined in the profile schema, and we didn't want to require that these two dates always existed as built-in profile properties.  Instead we consider these to be administrative information about the profile.  For convenience we added the properties to the base profile type so that developers wouldn't have to explicitly write the code to both load the profile data, and then look up these two tracking dates.  Instead we lazy load the two dates from the default provider the first time they get accessed.  Realistically though we don't expect developers to normally access these values for anything other than non-admin purposes.

Hope this helps,

Scott

P.S. The benefit of the provider model is that you can swap-in implementations of your own if you want too.  This gives you the benefit of a single API that multiple apps or app frameworks can standardize around, but also all the flexibility of customization if you want.  So I'd definitely recommend investigating how to use the built-in APIs where possible.

# August 3, 2006 4:19 PM

Jeff said:

Nope... I've got one line on Page_Load looking at a string. That certainly shouldn't be triggering a save by your description.

# August 3, 2006 5:48 PM

ScottGu said:

What does your overall profile definition look like?

And have you tried the automaticSaveEnabled="false" setting I suggested above?

# August 3, 2006 6:04 PM

Morri said:

I hacked this problem by editing one of the stored procs that the profile calls. Sorry I can't remember the name of the proc, but shouldn't be to hard to find it. The stored proc had an update for lastactivitydate, and by removing the update I managed to get users Gender without updating the lastactivitydate.

It seems kinda hazardous, but it hasn't caused any unwanted behaviour in our ~300 user app.

# August 4, 2006 1:09 AM

calabonga said:

The name of the proc is "aspnet_Profile_GetProperties"

# September 3, 2007 5:45 PM

youngtexas said:

<profile automaticSaveEnabled="false" /> works as indicated by ScottGu.

# September 18, 2007 5:11 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)