Dependency Injection is over Hyped

Dependency Injection frameworks have been over-hyped for too long. In most of the cases in which I have seen it touted as a perfect fit, it hasn’t really been necassary; And in some cases it made those applications harder to maintain than an alternative ‘Service Locator’ would have been. However, You can find some developers speaking as if you should avoid Service Location.

Update: I removed a quote from Nathan Evans, since he felt is was taken out of context. He says that he does not object to Service Location as a whole, and I will have to take him at his word on that. He does show some usage of Service Locator in his blog entry in the references below. I had thought he meant it was always bad, and not just when used within an IoC framework. There are plenty of other authors in the last 6 months that have clearly been against Service Locator. See the references below.

And on this blog and elsewhere you have developers such as me accepting provider model, a service locator, as a viable pattern; and accepting that dependency injection is also viable. Elsewhere you have dependency injection evangelists bashing provider model and any form of Service Locator. In the middle you have Martin Fowler.

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.”

‘Dependency Injection’ is only one form of the D in the SOLID design principles, ie. Dependency Inversion. I do highly recommend Dependency Inversion in any application that has a need to interact with dynamic data, or that has any level of business logic. Both Service Locator and Dependency Injection can be an anti-pattern or a viable pattern depending on the scenario.



MVC Controllers

Microsoft MVC does support Dependency Injection frameworks by having a dependency resolver to create any MVC controller factories, model binders, view engines and more. On the other hand it does this using IDependencyResolver which follows the Service Locator pattern.

A controller is an application specific implementation of page flow logic. If you need to change that logic you then should just do so in your application and redeploy. There shouldn’t be a need to have a Dependency Injection framework inject your controller instance for you. Just let the MVC framework handle instantiation normally. The reason most developers inject their controllers is so that the dependencies they need can be injected into them. This seems like a lazy excuse by a Dependency Injection framework. Maybe a better implementation strategy would be post compilation manipulation by a Dependency Injection ‘Tool’, similar in some ways to PostSharp. (I am not part of or affiliated in any way with PostSharp. My only connection is as a customer.)

Here is a typical example of a controller that I have seen in applications using Dependency Injection. This would look the same for any dynamic proxy based Dependency Injection framework. The Dependency Injection framework specific pieces are in application configuration and in bootstrapping code which sets the IDependencyResolver to be used.

using System;
using System.Globalization;
using System.Web.Mvc;
public namespace MyMvcApplication.Controllers
{
	//A controller using Dependency Injection
	public class SomethingController : Controller
	{
		private UserProvider _userProvider;
		private ILog _logProvider;
		private SomethingProvider _somethingProvider;
		private SomethingFormatter _somethingFormatter;

		public SomethingController(UserProvider userProvider,
			ILog logProvider,
			SomethingProvider somethingProvider,
			SomethingFormatter somethingFormatter)
		{
			_userProvider = userProvider;
			_logProvider = logProvider;
			_somethingProvider = somethingProvider;
			_somethingFormatter = somethingFormatter;
		}

		public ActionResult Index()
		{
			var user = _userProvider.GetUser(...);
			if (user.SomeCondition){
				_logProvider.Warn(...);
			}
			var something = _somethingProvider.GetSomething(...);
			var model = new SomethingViewModel() { item=something, formatter = _somethingFormatter };
			return View(model);
		}
	}
}

Is there any value in the Controller being injected in this scenario? Is this controller logic going to swapped out with another controller derived from SomethingController? The answer is, very unlikely. The business rules are in the injected providers, and not in the controller. All the controller does is define the actions available, the parameters to those actions, and then pass off all the real work to the providers. Those providers are what you may want to swap out with another implementation someday. So why not just stick to Service Locator in the controller?

Here is the equivalent controller using Service Locator.

using System;
using System.Globalization;
using System.Web.Mvc;
using Candor.Configuration.Provider;
public namespace MyMvcApplication.Controllers
{
	//A controller using Service Locator
	public class SomethingController : Controller
	{
		private ILog _logProvider;
		public ILog LogProvider
		{
			get { return _logProvider ?? (_logProvider = LogManager.GetLogger(typeof(SomethingController))); }
		}

		public ActionResult Index()
		{
			//option 1 for Service Locator (Candor ProviderResolver - definition shown below)
			var user = ProviderResolver<UserProvider>.Get.Provider.GetUser(...);
			if (user.SomeCondition){
				LogProvider.Warn(...);
			}
			//option 2 for Service Locator (traditional provider model)
			var something = SomethingManager.GetSomething(...);
			var model = new SomethingViewModel() { item=something }; 
			//view model handles getting (service locating) a reference to its own formatter.
			return View(model);
		}
	}
}

With service locator you don’t need to configure your MVC application to use a dependency resolver, as you would need to do with any of the dependency injection frameworks. Which is less code? More importantly, which is easier to debug an issue during dependency resolution?

Also note, that with Service Locator the controller doesn’t need to inject every provider type that every downstream class needs to use. It only needs to worry about the provider type(s) it uses directly. The example above is the ‘SomethingFormatter’, which is not directly used by the controller.

Both of these examples could be refactored to move the check of the current user down into the business layer of ‘SomethingProvider’, and therefore the implementation(s) of the provider. That would leave the action method as 3 statements: a business layer call, view model instantiation, and passing the view model into the view. Ideally, that is all any GET action method would consist of (as seen within the controller code).

Dependency Injection uses Service Locator

Under the covers when objects are instantiated they are created by a Service Locator. Here is some code using Spring Dependency Injection to get a reference to transaction support classes. This is not the recommended way to get Spring transaction support, but it is documented as a way in case you need more flexibility than the recommended code. My point here is to show that dynamic proxy based Dependency Injection frameworks also use Service Locator as an implementation detail, even if you don’t normally see it.

var tmpl = Spring.Context.Support.ContextRegistry.GetContext()
   .GetObjectsOfType(typeof(IPlatformTransactionManager));
IPlatformTransactionManager trans = null;
foreach (var x in tmpl.Values)
{
   trans = (IPlatformTransactionManager)x;
   break; //get first
}
//TODO: use 'trans' here

Minimal Provider Service Locator – the static ‘Manager’

Provider model traditionally has a counter part static class to resolve the provider implementation collection, and an ‘active’ main provider. It is responsible for loading the possible providers from configuration and making those provider types available for instantiation. The pattern typically dictates that there is a static member on this static class for every member of the provider type, which delegates the call to the active provider instance. This is not a real requirement of the pattern.

You can minimize this static class to have 2 simple properties which delegate the real work to a shared library class. The following example leverages the Candor.Configuration.Provider.ProviderCollection in the Candor.Core NuGet package (source on Github).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Candor.Configuration.Provider;

namespace Candor.NexulSoftware
{
    public static class ContactRequestManager
    {
        private static ProviderCollection<ContactRequestProvider> providers_ = null;
        public static ContactRequestProvider Provider
        {
            get { return Providers.ActiveProvider; }
        }
        public static ProviderCollection Providers
        {
            get
            {
                if (providers_ == null)
                    providers_ = new ProviderCollection<ContactRequestProvider>(typeof(ContactRequestManager));
                return providers_;
            }
        }
    }
}

You use methods on the configured provider using the Provider property on the static class.

ContactRequestManager<ContactRequestProvider>.Provider.SaveContactRequest(request, result);

In this example the ContactRequestManager is your Service Locator. For each type of provider you would have a separate static Service Locator class.

Provider Model DependencyResolver

You can take the example in the previous section a step further by reducing down to a single service locator for all your provider types. Even simpler you can just put this class into a shared library. I have made it available in the Candor.Common 0.7.0+ NuGet package (namespace Candor.Configuration.Provider).

I have only just started using this implementation of a Service Locator, so it may not have all the kinks worked out yet. Let me know if you have any constructive feedback.

using prov = System.Configuration.Provider;

namespace Candor.Configuration.Provider
{
    ///
    /// A bridge between applications using Provider model and depedency injection.
    ///
	/// ... snipped samples ... they are in article below.
    public class ProviderResolver<T>
        where T : prov.ProviderBase
    {
        private ProviderCollection<T> _providers;
        
        /// <summary>
        /// Gets the active provider from the <see cref="Providers"/> collection.
        /// </summary>
        public T Provider
        {
            get { return Providers.ActiveProvider; }
        }

        /// <summary>
        /// Gets or sets the configured providers (xml or code config).
        /// </summary>
        /// <remarks>These are lazy loaded on the first and only first request.
        /// If the value is set to null it will be reloaded again as needed.
        /// In the code configuration example you can set this to a collection of
        /// desired providers and then it will not be loaded from configuration xml.</remarks>
        public ProviderCollection<T> Providers
        {
            get
            {
                if (_providers == null)
                    _providers = new ProviderCollection<T>(typeof(T));
                return _providers;
            }
            set { _providers = value; }
        }

        /// <summary>
        /// Appends another provider and returns the resolver for chaining purposes.
        /// </summary>
        /// <param name="provider">The provider instance to append.</param>
        /// <returns></returns>
        public ProviderResolver<T> Append(T provider)
        {
            Providers.Add(provider);
            return this;
        }

        /// <summary>
        /// Appends another provider instance and makes it the active provider, then returns the resolver for chaining purposes.
        /// </summary>
        /// <param name="provider">The provider instance to append.</param>
        /// <returns></returns>
        public ProviderResolver<T> AppendActive(T provider)
        {
            Providers.Add(provider);
            Providers.SetActiveProvider(provider);
            return this;
        }

        /// <summary>
        /// Gets the resolver instance for the generic type and lazy loads it as needed.
        /// </summary>
        public static ProviderResolver<T> Get
        {
            get
            {
                var resolver = (ProviderResolver<T>)ProviderResolverDictionary.Resolvers[typeof(T)];
                if (resolver == null)
                {
                    resolver = new ProviderResolver<T>();
                    //this one loads from configuration, since it wasn't configured
                    ProviderResolverDictionary.Resolvers[typeof(T)] = resolver;
                }
                return resolver;
            }
        }

        /// <summary>
        /// Sets the <see cref="Providers"/> collection to a new list and returns the resolver for further configuration.
        /// </summary>
        /// <returns></returns>
        public static ProviderResolver<T> Configure()
        {
            var resolver = new ProviderResolver<T> { Providers = new ProviderCollection<T>() };
            ProviderResolverDictionary.Resolvers[typeof(T)] = resolver;
            return resolver;
        }
    }
}

Here is the ProviderResolverDictionary used in the above code. It is not publically available in the API.

using System;
using System.Collections.Generic;

namespace Candor.Configuration.Provider
{
    ///
    /// An internal only dictionary of resolvers for all provider types.
    ///
    /// Used only by ProviderResolver
    internal static class ProviderResolverDictionary
    {
        private static Dictionary<Type, object> _resolvers;
        /// <summary>
        /// Gets the dictionary of resolvers.
        /// </summary>
        public static Dictionary<Type, object> Resolvers
        {
            get
            {
                if (_resolvers == null)
                    _resolvers = new Dictionary<Type, object>();
                return _resolvers;
            }
        }
    }
}

This option is a little more verbose in each usage of the provider, but you don’t have to define a static class for each type of provider. Here is a sample usage.

ProviderResolver<ContactRequestProvider>.Get.Provider.SaveContactRequest(request, result);

Configuration

Configuring The provider resolver is easy with either code configuration or xml configuration. To see traditional provider model xml and code configuration, see my older article Provider Model Enhanced in the references below.

Code Configuration

This code configuration would go somewhere in your application startup. In an MVC application create a separate file to hold the code configuration and then call it from your Global.asax.cs. Or do as shown here and use Web Activator, available via NuGet and Codeplex.

using Candor.Configuration.Provider;
using Candor.Security;
using MySomethingApp;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(MyMvcApplication.AppStart_RegisterProviders), "PreStartup")]
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(MyMvcApplication.AppStart_RegisterProviders), "PostStartup")]

namespace MyMvcApplication
{
    public static class AppStart_RegisterProviders
    {
        public static void PreStartup()
        {
            RegisterProviders();
        }
        public static void PostStartup()
        {
        }

        public static void RegisterProviders()
        {	//You can put this somewhere else if you have a different preferred startup code location.
			ProviderResolver<UserProvider>.Configure()
				.AppendActive(new Candor.Security.SqlProvider.UserProvider("sql") { PasswordRegexExpression = ".*"});

			ProviderResolver<SomethingProvider>.Configure()
				.Append(new MySomethingApp.SqlProvider.SomethingProvider("sql") { ConnectionName = "DefaultConnection"})
				.AppendActive(new MySomethingApp.CacheProvider.SomethingProvider("cache") { DelegateProviderName = "sql"});
        }
    }
}//this goes in the App_Start folder of an MVC application.

If you need to use different providers in various configurations then you can either use conditional compilation for the blocks that need to vary, or you could read a ‘CurrentEnvironment’ AppSetting and use that value to configure which providers to use or the parameters to be passed into them. However, most variations would be in the database connections, cache server names, and the like. Most of those settings will still be controlled and transformed by configuration transforms.



Xml Configuration

Here is the equivalent configuration if you are using the ProviderResolver. This would go in your web.config or your app.config as appropriate. It is similar to the configuration you would have for classic provider model when the providers are loaded by a Manager class. The only difference in the classic provider model case is the name of the ‘UserProvider’ node would be ‘UserManager’, and the ‘SomethingProvider’ node would be ‘SomethingManager’.

<configuration>
	<configSections>
		<sectionGroup name="Candor.Security">
			<section name="UserProvider" type="Candor.Configuration.Provider.ProviderConfigurationSection, Candor" />
		</sectionGroup>
		<sectionGroup name="MySomethingApp">
			<section name="SomethingProvider" type="Candor.Configuration.Provider.ProviderConfigurationSection, Candor" />
		</sectionGroup>
		<!-- ... other config sections here ... -->
	</configSections>
	<connectionStrings>
		<add name="DefaultConnection" connectionString="...snipped..." providerName="System.Data.SqlClient" />
	</connectionStrings>
	<Candor.Security>
		<UserProvider defaultProvider="sql" >
			<providers>
				<add name="sql" type="Candor.Security.SqlProvider.UserProvider, Candor.Security.SqlProvider"
					connectionName="DefaultConnection"/>
			</providers>
		</UserProvider>
	</Candor.Security>
	<MySomethingApp>
		<SomethingProvider defaultProvider="cache" >
			<providers>
				<add name="cache" type="MySomethingApp.CacheProvider.SomethingProvider, MySomethingApp.CacheProvider"
					delegateProviderName="sql"/>
				<add name="sql" type="MySomethingApp.SqlProvider.SomethingProvider, MySomethingApp.SqlProvider"
					connectionName="DefaultConnection"/>
			</providers>
		</SomethingProvider>
	</MySomethingApp>
	<!-- ... other config here ... -->
</configuration>

This is much more verbose than the code configuration. The other disadvantage of xml configuration is the lack of compile time checking for type names. However, It is easy to transform different providers in configuration transforms. And less commonly, you can change configuration at any time after deployment. I have used xml configuration more in the past, but I plan on using code configuration more often in the future.

References

Dino Esposito on the Simple Talk Blog: ASP.NET MVC: Resolve or Inject? That’s the Issue…
https://www.simple-talk.com/dotnet/.net-framework/asp.net-mvc-resolve-or-inject-that%E2%80%99s-the-issue%E2%80%A6/

Candor Developer Blog: Provider Model is a SOLID pattern
http://candordeveloper.com/2012/06/26/provider-model-is-a-solid-pattern/
See this article for examples of other blogs bashing Service Locator.

Candor Developer Blog: Provider Model Layered Architecture
http://candordeveloper.com/2012/07/05/provider-model-layered-architecture/

Candor Developer Blog: Provider Model Enhanced
http://candordeveloper.com/2012/06/24/provider-model-enhanced/

Nathan Evans’ Blog: IoC containers: where you define the seams of applications
http://nbevans.wordpress.com/2013/04/10/ioc-containers-where-you-define-the-seams-of-applications/

PostSharp – Developer Tool
http://www.postsharp.net/

Github: Candor Common Open Source Code
https://github.com/michael-lang/candor-common

NuGet: Candor.Core package details
http://nuget.org/packages/Candor.Core/

Update: A few developers against Service Locators:
On Service Location
http://amy.palamounta.in/2012/10/26/on-service-location/

Some Servicelocator pattern stinks
http://www.jefclaes.be/2012/04/some-servicelocator-pattern-stinks.html

Update 4/11/2013, 9:30pm CST: I had to update the article to use xml syntax coloring, because the csharp syntax coloring stripped out all of my generics. If you know how to post C# code using generics on wordpress properly, please let me know.

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.

2 Comments

  • Avatar By Frisian

    Looking at your article from a Java point-of-view, I miss the distinction between dependency injection as such and dependency injection frameworks.
    Using dependency injection allows to configure objects per instance. Using a service locator on the other hand configures objects per class unless the service locator to be used is configurable itself (maybe by dependency injection?).
    The difference is most obvious with unit testing. With DI you mock the dependency and inject it into the object to be tested. With a service locator, you have to mock the dependency and the service locator to test an object.
    That said, in any non-trivial application there will be the need to configure objects of the same class in a different way and be it only for unit testing. The problem is, that you usually cannot foresee which object it will be, so – to be forearmed – you use dependency injection all the time.
    Using the usual trifecta of DI (constructor, setter, abstract getter) doesn’t tie your code to any DI framework. If nothing else works, you can do the plumbing yourself in the application code.
    Using annotations like @AutoWired on the other hand tie you to a DI framework. What’s worse, you have nothing gained in comparison to a service locator, because now it is just as difficult to configure instances of the same class in a different way within the same context.
    Besides, a web controller is not the best example for DI. It’s interface is tied to the web framework in use, because a controller is where the rubber meets the road. It being used with a different configuration is highly unlikely. Business or data access layer objects have application-specific interfaces and are much more likely to be used in different configurations.
    For example, some databases signal constraint violations right after the fact, whilst others only signal them after a commit. So, in order to deal with the subsequently thrown exceptions, you have to proxy either the data access object or the business object depending on the database in use.
    Lastely, even if DI is only the “D” in “SOLID”, it helps also with the “I”, because DI promotes the use of interfaces by making it easier to change the implementation.

  • Avatar By steve

    Always enjoy your blogs mike… You know I especially liked this one 🙂