Provider Model is a SOLID pattern

I have read lots of articles in the past couple years about provider model being either an anti-pattern, or not a pattern at all.  Most people would agree that you should strive for SOLID code when working in a languages that supports object oriented programming.  But no pattern is the only and best solution for any specific problem.

Dependency Injection (DI) and Provider Model (a Service Locator) both satisfy the D (dependency inversion) in SOLID.  Both are useful in the correct situations.

Martin Fowler: “The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.”

Usage scenarios

I primarily use provider model for business logic code and data layer code.  In the repository layer on Day 1 of an application I want to get my data from a mock/test implementation that serves up data from in memory and which resets every time I restart the application.  Then at some point I want to switch over to getting/saving data to a database.  Then sometime later I may want to inject a cache layer in front of the database implementation.  At some point in the future I may want to swap out the database implementation to get it from a webservice instead, with or without the cache layer in front of it.  This is all very easily accomplished via the provider model pattern.

In the business layer I typically start an application with one implementation of the logic and then evolve that single implementation over the course of that project.  Then on subsequent projects or specializations of that project I create a new business provider implementation specific to that project.  It typically inherits most of the logic from that base provider and then only override what changes for that project.

I will drill into each of these scenarios in another post.

Testability

Almost all of the opponents of provider model mention testability as a downfall of provider model.  This is the biggest myth about provider model in my opinion.  There are two aspects you may consider testing.  First that a given implementation works, and second that the correct instance is selected at run time.

Testing a given implementation of a provider implementation is the same as testing the implementation of any interface that gets injected.  Just instantiate the implementation provider, set the configuration option properties you want to test with, and call the method to be tested.  Simple.  What is so hard about that?

Testing selection of the correct instance requires a “Setup” method in your test fixture that adds provider implementations to the providers collection (See ‘code config’ below). Then the test methods in the test fixture can check the active “Provider” property on that static class to see that it is the correct type or call a method on the static class to see that it returns what your active type (presumably a mock) is hardcoded to return.

Unless you wrote your own implementation selector then you probably don’t need to test it.

Configuration

The primary way to configure a provider model abstraction is to use XML configuration in either your app.config or your web.config.  This is the only way as of today to configure some .net abstractions such as Membership and RoleManager.  However, the Microsoft use of provider model is not set in stone.  It can be done via code configuration in your own abstractions.

The “hidden complexity” of provider model configuration can inherently have the following problems at run time, according to Mark Seemann:

  • The appropriate configuration section is not available in the app.config file.
  • The ValidatorTypeName is not provided, or is null, or is malformed.
  • The ValidatorTypeName is correctly formed, but the type in question cannot be located by Fusion.
  • The Type doesn’t have a default constructor. This is one of the other problems of Constrained Construction: it can’t be statically enforced because a constructor is not part of an abstraction’s API.
  • The created type doesn’t implement IOrderValidator. [Or whatever your base provider type is]

Mark is implying that dependency injection frameworks do not have these problems by pointing these problems out as being a problem with provider model.  But until recently these problems were inherent in most DI frameworks.  Recently some DI frameworks have come up with the code config alternative.  Provider model also has this alternative.

Bootstrapping (Code config)

The base framework provider model static classes have getter only properties for the provider collection, “Providers”.  however, you are not limited to doing that in your own provider model implementations. You can add provider instances to your own provider model classes at application startup just as easily as any DI framework that has code config.

EmployeeManager.Providers.Add(new SQLEmployeeProvider("Db", "ConnectionName"));

This example takes in the required name of the base provider class, and the name of a connection in the connectionStrings configuration section to use for connecting to the database.  Your provider implementation can take in any parameters you need it to take, including either the name of a delegate provider, or an instance of another provider.  This is all up to you.  For instance if you want to cache your database calls you may do something like this:

EmployeeManager.Providers.SetActiveProvider(
	new AppFabricEmployeeProvider("cache"){
		DelegateProvider = EmployeeManager.Providers.Add(
			new SQLEmployeeProvider("db"){ 
				ConnectionName = "Primary"
		}) 
});

See my last post for a ProviderCollection that makes this work.

Lifetime management

This is a differentiating factor between provider model and other dependency injection frameworks.  Provider model only has one lifetime option, one instance at the application scope.  Your provider instance can have factory methods in it that return a new instance of some business model class for each call, but that is not part of the provider pattern itself.

If you need an instance per web request, or an instance per user session, then you may not want to use provider model.  Provider model itself does not support these other lifetime options, so if you want them you would have to code them yourself.  It may be better to use a full dependency injection framework if you need these other lifetime options.

Do you really need anything other than an application scope lifetime for a business logic layer or a data layer?  You should use a stateless layer for business logic.  That just means pass in all that is needed to perform the logic and don’t store any other state for a single request in the provider implementation.

Statics and Constrained Constructors

Mark Seemann: Basically it [Constrained Construction] occurs every time there’s an implicit constraint on the constructor of an implementer. In the case of Providers the constraint is that each implementer must have a default constructor.

Yes, this is true when you are using the more common XML configuration.  It is also required in other scenarios such as when using the serializable attribute on your model classes.  Why is this a problem?  A dependency injection framework also has the constrained constructor problem.  Most DI experts recommend using constructor injection.  This means you must define a constructor that takes all the essential services and all those services must be configured properly so that they can be passed in.  It is just a feature of the pattern in all three cases.  Is there a reason you can’t have a default constructor in an implementation for one of your business layer or data layer abstractions?  I’ve never seen a scenario where it was a problem, except when creating a singleton.  But if you have a valid case for and are creating a singleton class, then that won’t also be a provider implementation.  Just decide which pattern you need for a class and stick to it.

Many expert developers suggest that the static keyword should never be used.  Generally, I also steer developers away from static for variables; since you likely don’t really want shared state.  But it still comes down to what is appropriate for the scenario.  Static variables are not bad in all cases, but they are usually not what you really want.  This is just another case of any pattern or language feature can be misused by someone, but that doesn’t mean it should never be used.  Using static as part of a proven pattern that works, such as provider model, is perfectly acceptable.

The Dependency Injection Alternative

Dependency Injection is the other pattern for achieving dependency inversion.  There are numerous Dependency Injection frameworks available, such as Spring, Ninject, Castle Windsor and StructureMap to name a few of the major ones.

What I personally dislike about dependency injection frameworks is the dynamic proxy implementation.  I dislike having to inject classes that will never need to be swapped out for different implementations.  All of them I have seen require you to inject not only the classes you want to swap out, but also every class that needs an instance of that class, and every class that needs an instance of those classes, and on and on.  In an MVC application it ultimately requires your controllers to be injected.  Why would you ever want to swap out a different controller implementation via your DI framework configuration?  The reason developers need this is because of a limitation in their DI framework that requires it.  If you want different controller logic such as for deploying another vertical of your application; then you probably should just create a new web application with the same reusable business layer.

I have seen what I consider a valid use of a dependency injection framework.  See the Car and Engine example in Nate Kohari’s blog entry referenced below.  But the vast majority of Asp.Net MVC web applications that just want to swap getting data from a database to getting it from a webservice someday or passing it through a cache first; the full power of dependency injection just causes extra work with no real benefit.  However, you should use dependency injection when you want much finer control over lifetime, such as one instance per web request or one per user session.  Or maybe you can just use stateless methods in your provider model business layer.  There is no single correct answer.



References

Martin Fowler: Introduced the Dependency Injection idea
http://martinfowler.com/articles/injection.html (January 2004)

Mark Seemann: Author of Dependency Injection in .Net (2011)
http://blog.ploeh.dk/2011/04/27/ProviderIsNotAPattern.aspx
http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

Jacob Proffitt
http://scruffylookingcatherder.com/post/2008/06/13/Putting-Dependency-Injection-in-its-Place.aspx
http://scruffylookingcatherder.com/?tag=/Dependency-Injection 

Nate Kohari:  Creator of Ninject.
http://kohari.org/2007/08/15/defending-dependency-injection/

Oren Eini (Ayende @ Rahien): Creator of RavenDB and Rhine Mocks
http://ayende.com/blog/2718/dependency-injection-more-than-a-testing-seam
http://ayende.com/blog/2719/dependency-injection-iamdonquixote 
http://ayende.com/blog/2722/dependency-injection-applicability-benefits-and-mocking
 

About the Author

Michael Lang

Co-Founder and CTO of Watchdog Creative, business development, technology vision, and more since 2013, Developer, and Mentor since 1999.

See the about page for more details.

4 Comments

  • By gprayback

    Good article, and good rebuttal to Mark Seemann’s post. I frequently make heavy use of this pattern in systems where there is a single, simple dependency that we want to invert, for example a logging system. There are positive and negative aspects to the approach, and you definitely want to chose it knowing the trade-offs. But in some cases I think it is superior to dependency injection as a dependency inversion model.

  • By Colin

    I appreciate this post.

    I see how instantiating instances of services at runtime provides compile-time validation that required interfaces are implemented, but that seems like a rather trivial, easily discoverable/fixable problem.

    On the other hand, a big design disadvantage with the DI approach is that you’re introducing less-easily maintained dependencies (on interfaces at least) throughout a system, specifically in cases where services SHOULD be global.

    For example, when catching an exception, a provider pattern for a universal logging class might offer the line:

    Logger.Log(exception);

    The Logger service in that case is very loosely coupled with the caller such that the dependency goes away simply by deleting the line. Additionally, utilizing the provide in code requires no changes to any constructor, property or instantiation code.

    Conversely, a more DI approach requires tighter-coupling between the concept of a logger and the consuming caller and requires more code to to wire the caller/service up.

    Specifically you require changes to…

    //the constructor
    Caller(ILoggingService toInject)

    //the properties
    ILoggingService Logger{ get; set; }

    //every instantiation of the caller, and there may be many unless you’re using
    //a black-boxed approach of automatic instantiation (which makes it provider-like)
    var caller = new Caller(loggingServiceInstance)

    Consider the situation where you already have an established codebase, and added logging only after having it partially established. It would require 2-3 times the amount of code changes to support your new logging service, which seems like a clear maintainability disadvantage to me.

    Furthermore, you’d be changing not only the internal implementation details, but a publicly-facing interface of the classes (the constructor), which violates the idea of information hiding, thus introducing a potentially breaking-change to existing consumers of the class.

    The advantage of DI, on the other hand, is that it’s easier to vary concrete instances on an abstraction on a case-by-case basis. That has real benefit in some cases, but in others, where you actually WANT one global service to be used, it only seems to add work and reduce maintainability by creating a tighter-coupling with dependencies (i.e. changing constructors and adding properties vs. solely using a provider’s services).

    • mlang74 By mlang74

      I appreciate your interest. I would encourage you to read the later articles in this category.

      http://candordeveloper.com/category/provider-model-pattern/

      By the way, provider model is DI, Dependency Inversion, also known as the D in SOLID code. This article does not dispute using DI, but rather encourages you to compare Dependency Injection to Provider Model (a Service Locator, still DI).

      Are you stating that Provider Model takes more code than a Dependency Injection alternative to add Logging capabilities to a codebase that has no logging yet? I would disagree with that. Check the later articles in the series to see how to remove the Manager class. But even with the Manager class, code I have written with Provider Model was less code overall than the equivalent code to accomplish the same in Spring.Net.