Provider pattern is an extremely useful pattern that allows you to write loosely coupled components in .Net framework. .Net CLR injects these components at run-time. The concept of provider model is very simple, yet extremely powerful. We create an abstraction for our components and define which concrete implementation we want to use in the configuration file. When the code executes, we can create an instance of the concrete component mentioned in the configuration file.
Using a Provider for Logging
Let’s look at a simple example to understand how providers work in .Net. Suppose I want to create two separate loggers. One will log to a file and second will log to the database. I want to be able to change these loggers very easily based on my needs. If I hard code one of these loggers in code then I cannot easily swap them when I want.
Now I will create an interface to solve this problem with a provider. Both loggers will implement it.
public interface ILogger { void Log(String data); }
Now I need to create logger classes that will implement this interface.
public class FileLogger : ILogger { public void Log(String data) { // Your code to log data to file goes here Console.WriteLine("Data Logged to file:" + data); } } public class DatabaseLogger : ILogger { public void Log(String data) { // Your code to log data to DB goes here Console.WriteLine("Data Logged to Database:" + data); } }
What is left now is to configure the logger that we want to use in the config file. To do this I simply created a key in config file and defined the fully qualified path of the logger class that I want to use.
<appSettings> <add key="LoggingProvider" value="ProvidersDemo.DatabaseLogger, ProvidersDemo"/> </appSettings>
Here ProvidersDemo.DatabaseLogger is the name of the class that I want to use for logging including the namespace and ProvidersDemo is the assembly name.
Once we have defined the provider we can use it in our application:
static void Main(string[] args) { // Get the provider name from the config file String providerName = ConfigurationManager.AppSettings["LoggingProvider"]; // Create instance of the provider ILogger provider = Activator.CreateInstance(Type.GetType(providerName)) as ILogger; // Now we can use the provider provider.Log("Some Sample text that we want to log"); }
All I am doing in code is to first get the fully qualified name of the logger from config file and create an instance of that class. Our code is using the ILogger abstraction and does not care about the concrete implementation as long as it gets any logger. Once we create instance of the provider we can simply use it to log data.
Now if we want to replace the database logger with file logger in program, all we need to do is change it in the configuration file:
<appSettings> <add key="LoggingProvider" value="ProvidersDemo.FileLogger, ProvidersDemo"/> </appSettings>
Now if you run the program again, you will see that our application would have started using the file logger class.
Summary
Providers provide a lot of flexibility and allow us to write extensible code in .Net framework. The concept is rooted from Strategy pattern and is extensively used by .Net framework itself. You might have used ASP.Net Membership providers in the past. Whenever you want to create a plug-able component, you can use providers and they will give you a lot of flexibility.