Focus on Microsoft Technologies - Tutorials, Articles, Code Samples.

Saturday, September 02, 2006

Provider Model Design Pattern in ASP.NET Applications

Introducing the Provider Design Pattern

The Provider Design Pattern is a pattern we've used in several of our ASP.NET Starter Kits, formalized in ASP.NET Whidbey, and one that we'll hope you'll start using for your applications, too. The theory of the pattern is that it allows us to define a well-documented, easy-to-understand API, such as our new Whidbey Membership APIs, but at the same time give developers complete control over the internals of what occurs when those APIs are called.

The pattern was officially named in the summer of 2002 when we were designing the new Personalization feature of ASP.NET Whidbey. We were struggling to design the "right" schema that worked for everyone—the Personalization feature of ASP.NET Whidbey adds a new Profile class to which you can add strongly typed properties, for example, FirstName, whose values are stored in a database. The problem was that we needed a flexible design, but at the same time we wanted it to be easily extensible without everyone having to be a DBA; turns out this simple requirement is an incredibly challenging problem.

On the one hand, we could have designed the system to be entirely schema driven. This would have meant that we would have designed what I call, for lack of a better name, vertical tables in the database. Rather than using traditional columns, there would be a set of tables used to define the schema and a data table used to map data to a particular type. Each new item in the data table would correspond to a type in the schema table identifying what type of property it was. Below is a very simplistic data model of this design:

Figure 1. A simple model for personalization

Using this data model, we would see something like the data below in the Schema table:

Figure 2. Proposed schema table

And data in the PersonalizationData table similar to the data below:

Figure 3. PersonalizationData table

As you can see, this model maps the property type (such as FirstName) to a property value in the PersonalizationData table, such as FirstName: Rob.

While being infinitely flexible, this model starts breaking down with a large number of users and properties. For example, while testing this design, we used the data from the ASP.NET Forums. At the time, this was 200,000 users, each with about 15 properties. This resulted in 3,000,000 rows in the data table! An important benefit that SQL can provide, namely normalized data, is lost. We also knew that people would want to use standard SQL syntax for selecting from the tables for reporting and maintenance—for example, try running a report on this type of design for all who live in a certain zip code using the vertical table design—not easy!

The obvious solution was to use normal tables, but we didn't want users to have to call a DBA to modify the tables for incremental changes. For example, to add a new property called ZipCode would require adding a new column to the Person table.

The conundrum was that we could choose either a very flexible schema-based design that had scale limitations, or a super-scalable design that might be too inflexible for some people. Furthermore, beyond the simple data schema problems, we also wanted partitioned data access, and we wanted the Personalization APIs to be extensible. We wanted a lot!

What did we decide? Well, we decided that each customer scenario would be unique. We knew that we would eventually want to implement it ourselves on, and would want control over the data model. To solve the problem, we borrowed a pattern we had been experimenting with in the ASP.NET Forums.

The Pattern

The pattern itself is exceedingly simple and is given the name "provider" since it provides the functionality for an API. Defined, a provider is simply a contract between an API and the Business Logic/Data Abstraction Layer. The provider is the implementation of the API separate from the API itself. For example, the new Whidbey Membership feature has a static method called Membership.ValidateUser(). The Membership class itself contains no business logic; instead it simply forwards this call to the configured provider. It is the responsibility of the provider class to contain the implementation for that method, calling whatever Business Logic Layer (BLL) or Data Access Layer (DAL) is necessary.

There are some rules for how a provider behaves. A provider implementation must derive from an abstract base class, which is used to define a contract for a particular feature. For example, to create a membership provider for Oracle, you create a new class OracleMembershipProvider, which derives from MembershipProviderBase. The feature base class, for example, MembershipProviderBase, in turn derives from a common ProviderBase base class. The ProviderBase class is used to mark implementers as a provider and forces the implementation of a required method and property common to all providers. Figure 4 gives an example of the inheritance chain.

Click here for larger image.

Figure 4. A provider inheritance chain

The implementer must also define a configuration section entry used to load the provider. Below is an example of what this configuration entry looks like (borrowed from the ASP.NET Forums):

Continue the article

Post a Comment