The Evolution of .NET Dependency Resolution

Introduction

Dependency Resolution (RS), Dependency Injection (DI) and Inversion of Control (IoC) are hot topics nowadays. Basically all frameworks are aware of it, or offer some mechanisms to help implement it. It all started a long time ago, however, and things are slightly confusing at the moment – but will get better!

In this post, I won’t go through all of the details of all dependency resolution libraries in existence, instead I will only focus on Microsoft libraries. Also, I will only talk about generic dependency resolution, leaving out more specialized usages, such as WCF, WF and SharePoint, which also use similar concepts.

Origins

It all started with the venerable IServiceProvider interface. It basically provided a single method, GetService, that gave answer to “get me an implementation for this type”. That was it, the single parameter was a Type, and the response, a single object. There were no public implementations of it, but Windows Forms designers – auto generated code - used it a lot to request services from the design surfaces (aka, Visual Studio designer). You were free to implement it in any way, the only recommendation was to return null in case no service could be found, instead of throwing an exception.

ASP.NET MVC

ASP.NET MVC started as a built-in template option in Visual Studio but then migrated to NuGet deployment, which is how Microsoft now delivers its fast-moving libraries. MVC 4 introduced its own dependency injection container and API. It was built around IDependencyResolver interface, which did not implement IServiceProvider. although it offered a GetService method that had exactly the same signature – and requirements – as IServiceProvider’s. It also added another method, GetServices, for retrieving all implementations of a given service, again identified by its Type.

This time we had a registration point, which was DependencyResolver.Current. You could set it to your custom implementation, or use the default, which didn’t really return anything.

ASP.NET Web API

Web API came out a bit later than MVC, and, while sharing its philosophy, and also being delivered through NuGet, offered its own APIs, namely, for dependency injection. There was also a IDependencyResolver interface, again, not inheriting from IServiceProvider, but with a slightly more complex inheritance: now we had also IDependencyScope, which was where the GetService and GetServices methods were declared, as well as IDisposable, supposedly so that we could have dependency resolution scopes. The well-known registration point was GlobalConfiguration.Configuration.DependencyResolver.

ASP.NET SignalR

SignalR was something of an outsider in the ASP.NET stack. Like MVC and Web API, it was offered (and still is, for that matter) as a separate NuGet package. No wonder that it also offered its own dependency resolution API, in the form of IDependencyResolver. Again, not related to IServiceProvider, and as such offered a couple of other methods: besides the classic GetService (same signature and contract), we also had GetServices, and even a registration method (RegisterType with a couple of overloads). It was also IDisposable, perhaps to control registration scopes. The registration point was available as GlobalHost.DependencyResolver and there was a default implementation, appropriately named DefaultDependencyResolver.

Entity Framework 6

Leaving ASP.NET land for a moment, Entity Framework 6 also introduced its own (of course…) API for dependency resolution. The IDbDependencyResolver also offered the now classic GetService and GetServices methods, but this time, these also took an optional key parameter. GetService should not throw if a matching service was not found, and GetServices should return an empty enumeration likewise. The registration was done through DbConfiguration.DependencyResolver, no public default implementation. EF 6 expected a number of services to be supplied through dependency resolution, otherwise, it would use its own built-in defaults.

Entity Framework 7

Although still in pre-release, EF 7 shuffles things a bit. For once, the DbContext constructor can now take an instance of IServiceProvider. More details coming soon, I guess, but apparently it seems to be going back to the roots.

Unity

Unity is part of Microsoft’s Enterprise Library and long time readers of my blog should know that it’s what I normally use for inversion of control (IoC), dependency injection (DI) and aspect-oriented programming (AOP). Being an IoC container, it includes its own API, IUnityContainer, which also offered service resolution methods, besides lots of other stuff; this time, the names are Resolve and ResolveAll, with several overloads and generic as well as non-generic versions. Resolve can take an optional key, but a major difference is that the default implementation (UnityContainer) will throw an exception if a service is not found.

Common Service Locator

Because there are lots of dependency resolution libraries out there, offering conceptually similar services but with different APIs, Microsoft sponsored an open-source library for defining a common interface for dependency resolution to which interested parties could comply, or, better, write an adapter for. The code is available in Codeplex and NuGet and several library authors provided adapters for the Common Service Locator, such as Unity, Castle Windsor, Spring.NET, StructureMap, Autofac, MEF, LinFu, Ninject, etc. See a list of NuGet packages matching Common Service Locator here. The Common Service Locator API only prescribes two families of methods in its IServiceLocator API: GetInstance and GetAllInstances. Interestingly, IServiceLocator inherits from IServiceProvider, and it also features an optional key for GetInstance, like EF6 and Unity, as this is the more general case – multiple registrations for the same type under different keys, the default key is null.

ASP.NET 5.NET Core

ASP.NET 5 is just around the corner, and Microsoft seems to me to be moving in the right direction. MVC, Web API and SignalR are merged together, so the dependency resolution mechanisms should be the same. The IServicesCollection (sorry, no public API documentation) interface allows for the registration and the resolution of services through the conventional Startup.ConfigureServices method and is made available in the HttpContext and IApplicationBuilder implementations as the ApplicationServices and RequestServices properties, of type IServiceProvider. Not that you typically need it, but the default implementation of IServicesCollection is ServicesCollection, and one key difference is that you do not have a global entrypoint to it, you can only access it through the current HttpContext reference, in most cases.

Conclusion

That’s it. Looking forward for your feedback on this.

                             

2 Comments

  • I am a fan of the IServiceLocator interface, specifically because it decouples the service registration (which IMHO should happen all at once during application bootstrapping/startup) and the service resolution, which can be used by runtime implementations. As a concrete example I would set up all my dependencies in the Application_Start() method of Global.asax.cs (if using ASP.NET) and then if I had factory classes they would depend on an instance of IServiceLocator and would return the correct strategy implementation based on the string key that was passed (which of course would simply be a pass-through call to `serviceLocator.GetInstance<IMyStrategy>(someKey)`.

    Given that history, I'm not crazy about the fact that the interfaces for registration and resolution have been combined. Exposing the ability to register new services at runtime seems a bit like handing over a loaded gun. On the other hand it *does* offer flexibility and you are of course free not to use it, which is probably the route I'll take.

  • Hi, S!
    Coming out shortly, a post on ASP.NET 5 dependency resolution.

Add a Comment

As it will appear on the website

Not displayed

Your website