Introduction
In a nutshell, the provider model is a design pattern largely used by Microsoft components for allowing an application to make use and choose from multiple implementations of a given contract based on the settings of a configuration file. So, for instance, management of user membership or roles are usually carried out by means of classes based on this pattern (see MemberShipProvider or RoleProvider classes). This way, the application can choose the default provider for dealing with membership or roles, add or remove providers, etc. in a declarative way. It brings a lot of benefits for developers as they can plug new components easily without refactoring code.
Background
In the Microsoft world, providers must inherit from ProviderBase
abstract class (System.Configuration.Provider
namespace in System.Configuration.dll
, System.Configuration.ConfigurationManager.dll
assemblies).
Derived provider classes are configured in a declarative way within a proper app.config
or web.config
file according to the type of application we are working with. So, we need some rules to write these settings and some classes to read data accordingly. We can implement all of this with a ProviderConfiguration
class able to read collection of providers and details for each one. On the other hand, the way for writing data in config files can be carried out by means of configSections
(see <configSections />
node in the app.config
displayed at the bottom).
As said before, if we are going to deal with multiple providers we need an object to store the list of providers. This can be achieve with a ProviderCollection
class holding the list of configured providers.
Finally, we need a LogProviderManager
class able to:
- Read and expose all the configuration data by using the
ProviderConfiguration
class.
- Instantiate and expose the list of providers by placing them in a
ProviderCollection
class.
- Expose the default provider by some public default property.
Sample
Let's suppose we need to provide options for logging information in plain text or xml depending on application requirements. It would be a very good case to implement it by using the provider pattern. Not only developers would be able to choose between these implementations but they could create new ones as well and plug them very easy. See the class diagram displayed below:
LogProviderManager
class instantiates the LogProviderCollection
based on the configuration settings exposed by LogProviderConfiguration
class. The default provider along with the collection of log providers are exposed by LogProviderManager
by means of properties Default
and Providers
. Additionally, LogProviderManager
exposes the ProviderSettingsCollection
by means of ProviderSettings
collection.
Here is the app.config
file for more clarification:
<configuration>
<configSections>
<section name="LogProviders"
type="ProviderPatternLogTest.LogProvider.LogProviderConfiguration, ProviderPatternLogTest"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<LogProviders default="XmlProvider">
<providers>
<add name="XmlProvider"
type="ProviderPatternLogTest.LogProvider.Providers.XmlLogProvider, ProviderPatternLogTest"
fileLocation="c:\temp\log.xml"/>
<add name="TextProvider"
type="ProviderPatternLogTest.LogProvider.Providers.TextLogProvider, ProviderPatternLogTest"
fileLocation="c:\temp\log.txt"/>
</providers>
</LogProviders>
</configuration>
Notice that configuration of providers should contain a name
and a type
attribute containing the provider name and the fully qualified class name implementing the provider. The rest of attributes are optional (fileLocation
above) and serve to incorporate values for new customized provider properties. They will be returned in a System.Collections.Specialized.NameValueCollection
property for each ProviderSetting
object within ProviderSettings
collection property in LogProviderConfiguration
or LogProviderManager
classes.
Having said that, all developers have to do is to use the LogProviderManager.Default
property to get an instance of the default provider and then, call the exposed methods on it.
References
Please, take a look at here for accessing the original post from which this one was written. You can also download the source code from there.