The ASP.NET Provider Model

 

The ASP.NET Provider Model

There's a well-known design pattern behind the ASP.NET provider model the strategy pattern. Defined, the strategy pattern indicates an expected behavior (say, sorting) that can be implemented through a variety of interchangeable algorithms (say, Quicksort, Mergesort). Each application then selects the algorithm that best fits while keeping the public, observable behavior and programming API intact.

The most notable feature of the strategy pattern is that it provides a way for an object, or an entire subsystem, to expose its internals so that a client can unplug the default implementation of a given feature and plug his own in. This is exactly what happens in ASP.NET for a number of services, including membership, roles, state management, personalization, site navigation. The ASP.NET provider model is the ASP.NET implementation of the strategy pattern.

The Rationale Behind the Provider Model

The provider model is not an application feature that end users can see with their own eyes. In itself, it doesn't make an application show a richer content, run faster, or be more responsive. The provider model is an infrastructural feature that improves an application's architecture by enabling developers and architects to operate under the hood of some system components. At the same time, it enables developers to build new components that expose hooks for clients to plug in and customize behavior and settings. Implementing the strategy pattern doesn't transform an application into an open-source project, allowing anybody to modify anything. It simply means that you have a simple, elegant, and effective pattern to make certain parts of your application customizable by clients. At the same time, the ASP.NET implementation of the pattern the provider model makes you capable of customizing certain parts of the ASP.NET runtime environment through special classes named providers from which you can derive your own.

Exemplifying the Provider Model

To see an example of the provider model and its major benefits, let's look at Figure 1-6. The figure outlines the classic schema for authenticating a user. The blocks of the diagram follow closely the flow of operations in ASP.NET 1.1.

image from book
Figure 1-6: Classic membership schema for ASP.NET 1.1 applications.

The user who attempts to connect to a protected page is shown a login page and invited to type credentials. Next, the name and password are passed on to a function, which is ultimately responsible for validating the user. ASP.NET 1.x can automatically check users against Windows accounts or a list of names in the web.config file. None of these approaches work well in a realistic Web application; in most cases, developers just end up writing a custom piece of code to validate credentials against a homemade data source. The schema and storage medium of the data source are fixed and determined by the developer. Likewise, the algorithm employed to validate credentials is constrained by the design.

Is there anything wrong with this solution? Not necessarily. It works just fine, puts you in control of everything, and can be adapted to work in other applications. The rub is that there's no well-defined pattern that emerges from this solution. Sure, you can port it from one application to the next, but overall the solution relates to the adapter pattern mostly like cut-and-paste relates to object-oriented inheritance.

Let's briefly consider another scenario session state management. In ASP.NET 1.x, you can store the session state in a process separate from the running application be it SQL Server or a Windows service (the ASP.NET state server). If you do so, though, you're constrained to using the data schema that ASP.NET hard-codes for you. Furthermore, imagine you're not a SQL Server customer. In this case, either you abandon the idea of storing session state to a database or you buy a set of licenses for SQL Server. Finally, there's nothing you can do about the internal behavior of the ASP.NET session module. If you don't like the way it, say, serializes data to the out-of-process storage, you can't change it. Take it or leave it there's no intermediate choice.

Can you see the big picture? There are modules in ASP.NET that force you to take (or leave) a fixed schema of data, a fixed storage medium, and a fixed internal behavior. The most that you can do is (sometimes) avoid using those modules and write your own from scratch, as we outlined in the membership example. However, rolling your own replacement is not necessarily a smart move. You end up with a proprietary and application-specific system that is not automatically portable from one application to another. In addition, if you hire new people, you have to train those people before they get accustomed to using your API. Finally, you have to put forth a lot of effort to make such a proprietary API general enough to be reusable and extensible in a variety of contexts. (Otherwise, you get to reinvent the wheel time after time.)

In which way is the provider model a better solution? In the first place, it supplies a well-documented and common programming interface to perform common tasks. In addition, you gain the ability to completely control the internal business and data access logic of each API that falls under its umbrella.

In the end, in ASP.NET 1.1 you often have no other choice than writing your own API to roll certain functions the way you want. In ASP.NET 2.0, the provider model offers a much better alternative. So much better that it's practically a crime not to use it.

Figure 1-7 revisits Figure 1-6 in light of the provider model. ASP.NET 2.0 makes available a bunch of static methods on a global class Membership. (We'll cover the membership API in great detail in Chapter 15.) At the application level, you always invoke the same method to perform the same operation (for example, validating user credentials, creating new users, changing passwords.) Below this common API, though, you can plug in your own provider to do the job just the way you want. Writing a new provider is as easy as deriving a new class from a known base and overriding a few well-known methods. The selection of the current provider for a given task takes place in the configuration file.

image from book
Figure 1-7: Membership revisited to use the provider model in ASP.NET 2.0.

Benefits of the Provider Model

In the ASP.NET implementation, the strategy pattern brings you two major benefits: extensive customization of the application's run-time environment, and code reusability. Several areas in ASP.NET are affected by the provider model. You can write providers to handle user membership and roles, persist session state, manage user profiles through personalization, and load site map information from a variety of sources. For example, by writing a provider you can change the schema of the data used to persist credentials, store this data in an Oracle or DB2 database, and store passwords hashed rather than as clear text. This level of customization of system components is unprecedented, and it opens up a new world of possibilities for application developers. At the same time, it gives you an excellent starting point for writing new providers and even extending the model to your own components.

If you look at ASP.NET 2.0 from the perspective of existing applications, the provider model gains even more technical relevance because it is the key to code reuse and subsequent preservation of investments in programming and development time. As we pointed out, a realistic membership system in ASP.NET 1.1 requires you to roll your own API as far as validation and user management are concerned. What should you do when the decision to upgrade to ASP.NET 2.0 is made? Should you drop all that code to embrace the new dazzling membership API of ASP.NET 2.0? Or would you be better sticking to the old-fashioned and proprietary API for membership?

The provider model delivers the answer (and a good answer, indeed) in its unique ability of switching the underlying algorithm while preserving the overall behavior. This ability alone wouldn't be sufficient, though. You also need to adapt your existing code to make it pluggable in the new runtime environment. Another popular pattern helps out here the adapter pattern. The declared intent of the adapter pattern is convert a class A to an interface B that a client C understands. You wrap the existing code into a new provider class that can be seamlessly plugged into the existing ASP.NET 2.0 framework. You change the underlying implementation of the membership API, and you use your own schema and storage medium while keeping the top-level interface intact. And, more importantly, you get to fully reuse your code.

A Quick Look at the ASP.NET Implementation

The implementation of the ASP.NET provider model consists of three distinct elements the provider class, configuration layer, and storage layer. The provider class is the component you plug into the existing framework to provide a desired functionality the way you want. The configuration layer supplies information used to identify and instantiate the actual provider. The storage layer is the physical medium where data is stored. Depending on the feature, it can be Active Directory, an Oracle or SQL Server table, an XML file, or whatever else.

The Provider Class

A provider class implements an interface known to its clients. In this way, the class provides clients with the functionality promised by that interface. Clients are not required to know anything about the implementation details of the interface. This code opacity allows for the magic of code driving other code it doesn't even know about. In the ASP.NET provider model, the only variation to the original definition of the strategy pattern is that base classes are used instead of interfaces.

In ASP.NET, a provider class can't just be any class that implements a given interface. Quite the reverse, actually. A provider class must inherit from a well-known base class. There is a base class for each supported type of provider. The base class defines the programming interface of the provider through a bunch of abstract methods.

All provider base classes derive from a common class named ProviderBase. This base class provides one overridable method Initialize through which the run-time environment passes any pertinent settings from configuration files. Figure 1-8 outlines the hierarchy of provider classes for membership.

image from book
Figure 1-8: The hierarchy of provider classes.

image from book
Interfaces vs. Base Classes

Raise your hand if you are a developer who has never been involved in hours and hours of debate on the subject of interfaces versus base classes. It's a discussion that rarely comes to an end and always leave folks from different camps firmly holding to their respective positions. Should you use interfaces, or are base classes better? Which considerations is your answer based on? Consider the following fact, first.

Prebeta builds of ASP.NET 2.0 implemented the provider model literally with the definition of the strategy pattern that is, through interfaces. In the Beta 1 timeframe, interfaces were replaced with base classes, and so it is with the released version. The ASP.NET team seemingly came to a conclusion on the issue, did it not?

An interface is a collection of logically related methods that contains only member definitions and no code. An interface type is a partial description of a type, which multiple classes can potentially support. In other words, a good interface is one that is implemented by a number of different types and encapsulates a useful, generalized piece of functionality that clients want to use. That's why many interfaces just end with the suffix "able", such as IDisposable, IComparable, and IFormattable. If an interface has only one useful implementing class, it is likely the offspring of a bad design choice. As a practical rule, new interfaces should be introduced sparingly and with due forethought.

A base class defines a common behavior and a common programming interface for a tree of child classes. Classes are more flexible than interfaces and support versioning. If you add a new method to version 2.0 of a class, any existing derived classes continue to function unchanged, as long as the new method is not abstract. This is untrue for interfaces.

In light of these considerations, the emerging rule is that one should use base classes instead of interfaces whenever possible (which doesn't read as, "always use base classes"). To me, base classes appear to be an excellent choice, as far as the provider model is concerned.

The Configuration Layer

Each supported provider type is assigned a section in the configuration file, which is where the default provider for the feature is set and all available providers are listed. If the provider sports public properties, default values for these properties can be specified through attributes. The contents of the section are passed as an argument to the Initialize method of the ProviderBase class the only method that all providers have in common. Within this method, each provider uses the passed information to initialize its own state. Here's a snapshot of the configuration section for the membership provider.

<membership defaultProvider="AspNetSqlProvider">    <providers>        <add name="AspNetSqlProvider"            type="System.Web.Security.SqlMembershipProvider, System.Web"            connectionStringName="LocalSqlServer"            enablePasswordRetrieval="false"            enablePasswordReset="true"            requiresQuestionAndAnswer="true"            :            passwordFormat="Hashed" />        :    </providers> </membership> 

The Storage Layer

All providers need to read and write information to a persistent storage medium. In many cases, two providers of the same type differ only for the storage they employ. Details of the storage medium are packed in the attributes of the provider in the <providers> section, as shown in the preceding code sample. For example, the preceding AspNetSqlProvider provider is the predefined membership provider that reads and writes to a SQL Server table. The connection string for the provider is specified through the connectionStringName attribute, which in turn refers to another centralized section of the configuration files that lists all available connection strings.

For the provider to work, any needed infrastructure (that is, database, tables, relationships) must exist. Setting up the working environment is a task typically accomplished at deployment time. ASP.NET makes it a breeze thanks to the Web site administration console, which is shown in Figure 1-9.

image from book
Figure 1-9: The ASP.NET Web site administration console you invoke from within Visual Studio .NET 2005.

Available Types of Providers

The provider model is used to achieve several tasks, the most important of which are as follows:

Table 1-1 shows the list of the provider classes available in ASP.NET.

Table 1-1: Available ASP.NET Provider Base Classes

Class

Description

MembershipProvider

Base class for membership providers used to manage user account information.

ProfileProvider

Base class for personalization providers used to persist and retrieve user's profile information.

RoleProvider

Base class for role providers used to manage user role information.

SessionStateStoreProviderBase

Base class for session state store providers. These providers are used to save and retrieve session state information from persistent storage media.

SiteMapProvider

Base class for managing site map information.

The classes listed in Table 1-1 define an abstract method for each aspect that's customizable in the feature they represent. For example, regarding membership management, the class MembershipProvider exposes methods such as ValidateUser, CreateUser, DeleteUser, ChangePassword, and so forth. Note that you'll never use MembershipProvider in your code just because it's an abstract class. Instead, you'll use a derived class such as SqlMembershipProvider or, perhaps, ActiveDirectoryMembershipProvider. The same holds true for other types of providers.

Finally, if you're going to write a custom membership provider that wraps your existing code, you'd create a class that inherits from MembershipProvider or similar classes if other provider-based features are involved.

Note 

The provider architecture is one of ASP.NET 2.0's most important new features and also one of the most delicate with regard to applications. To prevent developers from producing buggy providers, the ASP.NET team supplies a made-to-measure provider toolkit that details what you can and cannot do in a provider, plus lots of sample code to serve as a guide. Writing a custom provider can be tricky for at least a couple of reasons. First, ASP.NET providers must be thread-safe. Second, their initialization step can lead you straight into a deadly reentrancy. Be sure you download the ASP.NET provider toolkit from the ASP.NET Developer Center before you leap into a new provider project.

 


Programming Microsoft ASP. Net 2.0 Core Reference
Programming Microsoft ASP.NET 2.0 Core Reference
ISBN: 0735621764
EAN: 2147483647
Year: 2004
Pages: 112
Authors: Dino Esposito
BUY ON AMAZON

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net