Why I've outgrown Membership and Profile
A couple of years ago, when I was less focused, finished with my book and completely unmotivated to develop anything useful for my own non-day job projects, I struggled trying to shoehorn my apps into the ASP.NET Membership and Profile API's. Probably because of my lack of experience, I became very frustrated at the point where the objects started to relate to the data.
It occurred to me fairly recently that these systems provide a level of abstraction that makes sense in terms of data storage, but you still have to do a fair amount of work in your providers to make sure you aren't pounding the data store. That means caching, of course, but you still might be creating objects in several places (handlers, the page, user controls, etc.), and each time you're going to the well, whether it be by way of the caching mechanism you create or going to the data store.
So why cache at all? Why not get the data once, early in the request cycle, and go back to it when you need it? Oddly enough, it was good old fashioned FormsAuth that made me think of this, where in ASP.NET v1.x we would look up the user and roles, probably in an HttpModule, and access that data from where ever.
Yes, you can do this today with a well-written Membership provider, but it's more complicated than it needs to be. Not only is the interface fairly large, but then you have to create the various objects during the page lifecycle which in turn call the various pieces of the provider. It just seems like a lot of work. It means that in every piece, you have to call something like Membership.GetUser(User.Identity.Name), invoking the provider methods.
What if you did something a little more simple. Heck, use the Membership API if you want to, but do it once. Create an HttpModule that goes something like this:
public class UserContext : IHttpModule
{
public void Init(HttpApplication application)
{
application.AuthenticateRequest += new EventHandler(application_AuthenticateRequest);
}
private void application_AuthenticateRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
MembershipUser user = Membership.GetUser(context.User.Identity.Name);
context.Items.Add("membershipUser", user);
}
public static MembershipUser Current
{
get
{
return (MembershipUser)HttpContext.Current.Items["membershipUser"];
}
}
public void Dispose()
{
}
}
Then all you need is to call UserContext.Current from your code and you've got access to all that your user object has to offer. I used Membership here, but you could roll your own too. In fact, you could make this an abstract class and leave the implementation of AuthenticateRequest to a derived class, specific to your app.
At first glance, this seems like a very small win, but how much do you use user objects around your page? Furthermore, how much plumbing have you written to implement caching? When you eliminate all of that, suddenly your code gets a lot more simple, and a lot easier to manage. If I had a half-dozen user controls on the page that all had to access my user, and maybe manipulate it, at least it only has to read once from the data store, and I'm free to not write a bunch of caching code for subsequent object creation.
One caveat here is that you do need to keep thread safety in mind. If you don't use asynchronous page or handler methods, you're OK, but keep that in mind.