A Look at ASP.NET 2.0's Provider ModelBy Scott Mitchell
Back in 2001 I started work on an ASP.NET online messageboard application called WebForums.NET. The idea was to create an ASP.NET-based messageboard system that could easily be plugged into an existing website. One particular challenge building such an end-to-end application was providing a means for customers to be able to integrate it within their system. For example, clearly an online forum needs some sort of data store to store user information, forums, posts, and so on, but what's important is not to lock the customer into a particular data store. That is, you shouldn't say, "I'm going to have my application use Microsoft SQL Server 2000," because at that point, how are customers who use Oracle or Access going to be able to use your software?
Another issue is with integration into a customer's existing data. All online forum sites have user accounts and
a means for creating new accounts; this is typically modeled in the forum's architecture as a
Users table in the
database. But customers might already have their own user-related database tables that already have thousands of user accounts.
Or a customer might want to use the forums in an intranet setting, authenticating and storing user information against
Active Directory, rather than some database table. When a forum software system creates a
Users database table
and says to the customer, "This is how you will store users," they alienate those customers who already have existing infrastructure
and user data. Clearly this challenge faces any company or developer that's creating software to be used "in the wild."
This particular challenge arises when you build a system with a rigid API implementation. Rather than providing a means
to customize the logic, a rigid API implementation hard codes the implementation details - you will use SQL Server as your
backend data store... you will have a
Users table in this database where all user information will
be stored. This rigidity, however, can be broken quite easily using the provider design pattern.
With the provider design pattern the system architect merely defines the API, the programmatic functionality offerred by the
system. For an online forum application, this might include a
Users class with methods like
The beauty of the provider model is that the customer implementing the solution can specify a custom class that the system should use.
This custom class must implement the system's well-defined API, but it allows for any custom implementation to be seamlessly plugged
in. That is, once this API is defined, the system implementor can create a default concrete implementation - one that uses
SQL Server and a
Users table - that most customers can use without modification. Those customers that have a
custom need - those that want to use Oracle or have user data stored in some other manner - can create classes that provide
the necessary functionality and plug them into the system.
The provider design pattern is used throughout ASP.NET 2.0. There are also guidelines on how to provide this functionality in ASP.NET 1.x applications. In this article we'll examine the provider model and see how it's used in ASP.NET 2.0. Read on to learn more!
Breaking the Rigid API Implementation
Fairly early on in my development of WebForums.NET I realized that the rigid API implementation was going to be a problem. Part of my design goal for the software was to make it as flexible and customizable as possible, and boxing users into using SQL Server and my implementation of the users data model seemed restrictive, at best. Unfortunately, I didn't have any insight into this problem, but luckily Andy Smith did. He suggested (and built!) a system that involved two pieces:
- A set of abstract base classes that defined the system's core functionality, and
- Code that would, at runtime, dynamically load a specified class that extended the abstract base class and use
its functionality. Specifically, the code inspected the
Web.configfile, which contained a
<ConfigSetting>that gave the fully-qualified name for the class to use.
Userstable. Customers that were happy with this configuration could just use the application as-is and everything would work fine without them needing to write a line of code. Those developers who needed to customize the solution for their unique needs, however, could do so by creating their own classes that derived from the appropriate abstract base class(es). They could have this new class used by the system by simply dropping the assembly in the application's
/bindirectory and updating the
Specifically, WebForums.NET shipped with an abstract base class called
DataProvider that spelled out all
of the methods in the system, akin to:
AuthenticateUser(username, password) and
spelled out two of the many methods defined by the system. The static
Instance() method was the workhorse of the
DataProvider class. It contained the code that inspected the
Web.config file for the WebForums.NET
configuration information, which indicated the fully-qualified name of the class the system was to use. The method then used
reflection (with caching) to create an instance of that class and return it to the system.
WebForums.NET shipped with a class called
SqlDataProvider that extended the
DataProvider base class,
providing concrete implementations for the assorted methods. For example, all methods in
with data stored in a SQL Server 2000 database; the user-related methods worked with a pre-defined
table. A customer who wanted to change the backend functionality could create her own class that derived from
indicating in the
Web.config file that their custom class should be used. For example, the
in WebForums.NET would include the following content:
This setting information, by default, referenced the
SqlDataProvider class that shipped with WebForums.NET.
However, if a customer created their own implementation of the API, they could provide their class's details here, and
the system would automatically start using their implementation in lieu of the default implementation.
With this architecture in place, the page developer working with the WebForums.NET could use code like the following to authenticate a user:
DataProvider.Instance() method is called, the configuration file is examined and an instance of the
appropriate class is returned. This would be the default
SqlDataProvider class if the customer has not created
their own implementation; it would be their own class if they did. Once the
returns an instance of the appropriate provider, we can simply invoke the members of the API,
in this example.
|The WebForums.NET Provider Model - An Early Prototype|
Andy's provider model had a few shortcomings that have since been accounted for in Microsoft's recommendations of using
the provider model. For one, WebForums.NET had a single abstract base class with all of the API defined in that
one class. The downside here was that if a customer wanted to customize only a small part of the system - such as how
user information was stored - he had to provide implementations for all of the methods in the system. A better approach is
to create an abstract base class for each logical entity in the system. For an online messageboard application this might
entail classes like |
Also, the code I've shown as WebForums.NET's implementation of the provider model has been changed a little bit to more closely look like the code used by Microsoft in ASP.NET 2.0. Andy's ideas were the precursor to the provider model, in my opinion, although Microsoft's implementation of the provider model is cleaner and more robust.
On an aside, WebForums.NET ended up being sold to Microsoft in March 2002. Rob Howard and others added a lot of features to the system and released it for free as the the ASP.NET Forums. Today Rob and crew have turned the ASP.NET Forums into Community Server, a blogging, forums, gallery, listserv, newsreader, and so on, all rolled into one. The concepts outlined and implemented by Andy are used today in both the ASP.NET Forums and Community Server, as well as in many core ASP.NET 2.0 components.
The Benefits of the Provider Model
The provider model offers a number of benefits. First, note that there's a clean separation between the code and the backend implementation. Regardless if whether or not the code to authenticate a user is done against a SQL Server 2000 database's
Userstable, or if it's done against an Active Directory store, the code from the page developer's perspective is the same:
DataProvider.Instance().AuthenticateUser(username, password). The backend implementation changes are transparent.
Since system architects are strongly encouraged to create a default concrete implementation, the provider model offers the best of both worlds: to those who are content with the default implementation, the system just works as expected; for those that need to customize the system, they can do so without upsetting the existing code or programmatic logic. This design pattern also makes prototyping and agile development a lot easier. For example, in the early iterations of working with the system, it might be easier to just use the default implementation. However, later you suspect you'll need to cusomize certain aspects in order to integrate the work with your company's existing systems. When that time comes, you can achieve the needed customization through the provider model, meaning your earlier work need not be changed to reflect the backend implementation changes.
Like many good design patterns, the provider model also affords separation of duties among developers. One set of developers can be tasked with mastering the system's API, while others can be tasked with focusing on the backend implementation and customization. These two groups can work on the system without stepping on one another's toes. Furthermore, if the system being worked on is an industry standard - like ASP.NET 2.0 - skills from both tasks can be easily carried over into future jobs.
The Provider Model in ASP.NET 2.0
ASP.NET 2.0 utilizes the provider model throughout its architecture. Many of its subsystems - Membership, Site Navigation, Personalization, and so on - utilize the provider model. Each of these subsystems provide a default implementation, but enable customers to tweak the functionality to their own needs. For example, the Site Navigation piece of ASP.NET 2.0 allows a page developer to define the navigational structure of their website. This data can then be used by a variety of Web controls, to display site maps, breadcrumbs, treeviews, or menus that highlight the site's navigation and/or show the user's location in the site. In addition to navigation-related Web controls, the site navigation API provides a bevy of methods for interacting with the website's navigation information
By default the site's navigational information must be encoded in a properly-formatted XML file. This is the data store that the default site navigation is hard-coded to use. However, ASP.NET 2.0's provider model makes it easy for you to use your own data store for site navigation. For example, in a project I'm currently working on a database contains information on what pages exist in the site and what permissions various users have for those pages. Rather than redefining this information in an XML file and having to try to keep two copies of this information up to date, in order to utilize the site navigation in ASP.NET 2.0 I will be able to simply create a provider class that works directly with the database information. Once this class is created and specified in the website's configuration, the navigation Web controls will be working against the application's custom navigation information stored in the database. (Note: as of the time of this writing, this project is still in ASP.NET 1.x. However, this example hopefully illustrates the benefit of the provider model.)
Personally I think that the provider model is one of ASP.NET 2.0's greatest features for migration. ASP.NET 2.0 offers a lot of new features that developers had to custom bake in 1.x. If these new features in 2.0 used rigid implementations, it would dissuade migration from 'living' 1.x applications that used custom solutions since many of the new ASP.NET 2.0 Web controls use these new subsystems. With the provider model in place, however, we can upgrade our 1.x apps to 2.0 and create a provider to have 2.0's new subsystems integrate with our custom baked solutions. That means when moving to 2.0 we can use the new Web controls and have them seamlessly use our existing systems thanks to the provider model.
|Examples of Custom Providers...|
Many developers have created custom providers to extend the built-in functionalities in the .NET Framework 2.0.
In Examining ASP.NET 2.0's Site Navigation - Part 4
I show how to build a custom site map provider that bases the site map's structure on the physical file system structure.
Jeff Prosise has created a custom site map provider for
On the membership, roles, and providers front, Scott Guthrie lists a number of custom providers in his ASP.NET 2.0 Membership, Roles, Forms Authentication, and Security Resources page. I've created a custom provider profile that serializes profile data to XML files; check it out at Examining ASP.NET 2.0's Membership, Roles, and Profile - Part 7. There's also a normalized custom SQL profile provider available from Microsoft.
See Microsoft's ASP.NET 2.0 Providers documentation for more information!
For More Information...
With the provider model an important architectural piece in ASP.NET 2.0, Microsoft has published a number of articles on this topic. If you are interested in learning more I'd encourage you to start with Rob Howard's two articles:
- Understanding and Extending the Site Navigation System in ASP.NET 2.0, by David Gristwood, and
- Custom Site Map Providers in ASP.NET 2.0, by Morgan Skinner
When creating systems that will be used by a number of customers with varying requirements, a rigid API implementation can rightfully cause a scare. A rigid implementation forces customers to meet, agree to, and become locked into the system architect's vision. Companies are oftentimes more interested in applications and frameworks that will work with their existing solutions rather than forcing them to coerce their solutions to work with the vendor's.
The provider model is one way to break the rigid implementation problem. With the provider model, the system is flexible enough to be able to use any class that extends a particular base class. Therefore, customers can create their own derived classes that include their custom logic and business rules. This new class can be seamlessly plugged into the system, without disturbing existing code shipped with the application or any new, custom code that has since been created. The provider model is heavily used in ASP.NET 2.0; the concepts can be applied to ASP.NET 1.x applications as well.