In a recent moment of clarity I finally realized why I've been having so many problems with ASP.NET's Membership and Role Providers. Surprisingly enough, it wasn't due to their extreme age. Instead, I determined that the reason I've been having so many problems with them was due to the fact that I've been using them incorrectly for years now.
My Experience with Providers
I still vividly remember how excited I was when I first learned of providers. (It was at a private software review on the Microsoft campus where Scott Guthrie was showcasing how cool it was now going to be for ASP.NET developers to just focus on their apps by leaving behind all the headaches associated with wiring up logins and rolling security functionality from near scratch all the time.) Over the years I've leveraged ASP.NET Membership and Role providers in a large number of sites and projects.
What I've liked about providers over the years is that fact that they were extensible—and let me define my own users and authorization. In other words, instead of using these providers out of the box (against access or attachable SQL Server databases), I've almost always used providers to either work against schema that I create, schema and data that already exist, or a non-database–driven set of authentication and authorization needs.
Only, over the last few years (especially since switching to ASP.NET MVC development and taking a more agile approach to development, I've noticed both how ASP.NET's providers are really starting to show their age and how they incur lots of negatives that really offset the only two benefits (authentication and authorization) that I've drawn from them.
My Problems with Providers
Among other things, one of the biggest problems I've had all along with ASP.NET's Membership and Role providers was the huge number of non-implemented methods that I'd always end up with when creating my own customized providers. Without creating customized providers, I'm at the mercy of ASP.NET—either in the form of running a few scripts against an existing database that would wire it up to store information about users and roles in schema that was written years ago (and which doesn't meet my picky standards or tastes) or in the form of blindly dropping that data into another, siloed database somewhere. Neither of those approaches has ever really met my business needs.
Furthermore, while the ASP.NET Membership provider provides methods for adding new sign-ups (or registering new users), changing passwords, retrieving lost passwords, and all that "stuff," I've never really found myself building the kind of application where I could just use those methods off the shelf. In fact, I still, personally, maintain that those methods are really only scoped or suited for a very subset of website types—such as forum sites and other "self-service" type sites. But in my case, creating sites has always required a more involved registration process, required payment, or needed to address business rules that were more complex than just letting end users self-register (to say nothing of the extra effort required to tweak custom providers in terms of password complexity or to allow usernames to be email addresses, and so on).
Consequently, whenever I end up implementing Membership or Role providers, what I always end up with is a single method (ValidateUser) that is implemented in my Membership provider, and a single method (GetRolesForUser) in my Membership providers as well. Otherwise, the other 37 members in these providers end up being "implemented" with "throw new NotImplementedException();" code.
That, and there's really no way to get around the fact that these providers end up being static objects—instantiated when the site first launches, and lingering around in memory until the app/site restarts. And, granted, I'm not worried about the performance overhead of having objects scoped that long, but as I reported previously, the static nature of these objects has burned me due to some poor choices on my part when it came to combining Linq to SQL contexts that cached data within these objects.
The True Nature of Providers
In the end, my moment of recent clarity was really two realizations.
First, that ASP.NET membership (and role management) really isn't about managing security: It's about managing users. Hence, the reason I've felt, for so long, that I've been kicking against the bricks with these providers is because I've been using them wrong, as I really don't need or want ASP.NET to control my membership. As a developer, I consider membership to be my responsibility—or something that almost always has to be managed via a set of complex business rules that I have to translate into each application.