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

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.

Unity, Part 11: Integrating With Azure Application Insights

Another one for the Unity series.

Lately I’ve been playing with Azure Application Insights. Nice thing, even if – at least, for the moment – not as powerful as some of its contesters. A thing that came to my mind almost immediately was how to integrate it with IoC containers like Unity.

I already talked about how to use AOP techniques in Unity. This time I will leverage on that and explain how we can use this knowledge to add insights into our application transparently.

We need the Application Insights SDK, which is available at GitHub in source code and conveniently as a NuGet package (all you need is Microsoft.ApplicationInsights):

image

I implemented an HandlerAttribute that is also an implementation of ICallHandler. Inside of it, I call the intercepted method and then log it to Application Insights through the TelemetryClient, a part of the Application Insights APIs. I added an option to set the instrumentation key, which uniquely identifies our Application Insights account and shouldn’t be shared. If not supplied, it will default to whatever is in

TelemetryConfiguration.Active.InstrumentationKey. Finally, we can decide to have the call asynchronous (so as to not cause delays to our application) or synchronous.

Here is the code for the interception attribute:

[Serializable]

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]

public sealed class TelemetryCallHandlerAttribute : HandlerAttribute, ICallHandler

{

    #region Public constructors

    public TelemetryCallHandlerAttribute()

    {

    }

 

    public TelemetryCallHandlerAttribute(string instrumentationKey)

    {

        this.InstrumentationKey = instrumentationKey;

    }

 

    public string InstrumentationKey { get; set; }

 

    public bool Async { get; set; }

 

    #endregion

 

    #region Public override methods

    public override ICallHandler CreateHandler(IUnityContainer ignored)

    {

        return (this);

    }

    #endregion

 

    #region ICallHandler Members

 

    IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)

    {

        TelemetryConfiguration config = null;

 

        if (string.IsNullOrWhiteSpace(this.InstrumentationKey) == true)

        {

            config = TelemetryConfiguration.Active;

        }

        else

        {

            config = TelemetryConfiguration.CreateDefault();

            config.InstrumentationKey = this.InstrumentationKey;

        }

 

        var telemetryClient = new TelemetryClient(config);

        var watch = Stopwatch.StartNew();

        var result = getNext()(input, getNext);

 

        var elapsedMilliseconds = watch.ElapsedMilliseconds;

        var exception = result.Exception;

        var returnValue = result.ReturnValue;

 

        var properties = new Dictionary<string, string>();

 

        for (var i = 0; i < input.Arguments.Count; ++i)

        {

            var key = input.Arguments.ParameterName(i);

            properties[key] = (input.Arguments[i] ?? string.Empty).ToString();

        }

 

        if (exception != null)

        {

            properties["$Exception"] = exception.Message;

        }

 

        if (returnValue != null)

        {

            properties["$ReturnValue"] = returnValue.ToString();

        }

 

        var metrics = new Dictionary<string, double>();

        metrics["ElapsedMilliseconds"] = elapsedMilliseconds;

 

        if (this.Async == false)

        {

            this.TrackEvent(telemetryClient, input.MethodBase.Name, properties, metrics);

        }

        else

        {

            this.TrackEventAsync(telemetryClient, input.MethodBase.Name, properties, metrics);

        }

 

        return (result);

    }

 

    private void TrackEvent(TelemetryClient telemetryClient, string name, IDictionary<string, string> properties, IDictionary<string, double> metrics)

    {

        telemetryClient.TrackEvent(name, properties, metrics);

    }

 

    private async void TrackEventAsync(TelemetryClient telemetryClient, string name, IDictionary<string, string> properties, IDictionary<string, double> metrics)

    {[Serializable]

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]

    public sealed class TelemetryCallHandlerAttribute : HandlerAttribute, ICallHandler

    {

        #region Public constructors

        public TelemetryCallHandlerAttribute()

        {

        }

 

        public TelemetryCallHandlerAttribute(string instrumentationKey)

        {

            this.InstrumentationKey = instrumentationKey;

        }

 

        public string InstrumentationKey { get; set; }

 

        public bool Async { get; set; }

 

        #endregion

 

        #region Public override methods

        public override ICallHandler CreateHandler(IUnityContainer ignored)

        {

            return (this);

        }

        #endregion

 

        #region ICallHandler Members

 

        IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)

        {

            TelemetryConfiguration config = null;

 

            if (string.IsNullOrWhiteSpace(this.InstrumentationKey) == true)

            {

                config = TelemetryConfiguration.Active;

            }

            else

            {

                config = TelemetryConfiguration.CreateDefault();

                config.InstrumentationKey = this.InstrumentationKey;

            }

 

            var telemetryClient = new TelemetryClient(config);

            var watch = Stopwatch.StartNew();

            var result = getNext()(input, getNext);

 

            var elapsedMilliseconds = watch.ElapsedMilliseconds;

            var exception = result.Exception;

            var returnValue = result.ReturnValue;

 

            var properties = new Dictionary<string, string>();

 

            for (var i = 0; i < input.Arguments.Count; ++i)

            {

                var key = input.Arguments.ParameterName(i);

                properties[key] = (input.Arguments[i] ?? string.Empty).ToString();

            }

 

            if (returnValue != null)

            {

                properties["$ReturnValue"] = returnValue.ToString();

            }

 

            var metrics = new Dictionary<string, double>();

            metrics["ElapsedMilliseconds"] = elapsedMilliseconds;

 

            if (this.Async == false)

            {

                if (exception != null)

                {

                    properties["Name"] = input.MethodBase.Name;

                    this.TrackException(telemetryClient, exception, properties, metrics);

                }

                else

                {

                    this.TrackEvent(telemetryClient, input.MethodBase.Name, properties, metrics);

                }

            }

            else

            {

                if (exception != null)

                {

                    properties["Name"] = input.MethodBase.Name;

                    this.TrackExceptionAsync(telemetryClient, exception, properties, metrics);

                }

                else

                {

                    this.TrackEventAsync(telemetryClient, input.MethodBase.Name, properties, metrics);

                }

            }

 

            return (result);

        }

 

        private void TrackException(TelemetryClient telemetryClient, Exception ex, IDictionary<string, string> properties, IDictionary<string, double> metrics)

        {

            telemetryClient.TrackException(ex, properties, metrics);

        }

 

        private async void TrackExceptionAsync(TelemetryClient telemetryClient, Exception ex, IDictionary<string, string> properties, IDictionary<string, double> metrics)

        {

            await Task.Run(() => this.TrackException(telemetryClient, ex, properties, metrics));

        }

 

        private void TrackEvent(TelemetryClient telemetryClient, string name, IDictionary<string, string> properties, IDictionary<string, double> metrics)

        {

            telemetryClient.TrackEvent(name, properties, metrics);

        }

 

        private async void TrackEventAsync(TelemetryClient telemetryClient, string name, IDictionary<string, string> properties, IDictionary<string, double> metrics)

        {

            await Task.Run(() => this.TrackEvent(telemetryClient, name, properties, metrics));

        }

 

        #endregion

    }        await Task.Run(() => this.TrackEvent(telemetryClient, name, properties, metrics));

    }

 

    #endregion

}

It will track the event under the called method name, and will send along a string representation of all its arguments, result value, exception thrown (if any) and elapsed time (TelemetryClient.TrackEvent or TelemetryClient.TrackException).

A simple usage, without providing the instrumentation key, would be:

[TelemetryCallHandler]

public virtual BusinessResponse PerformBusinessOperation(int businessId, string arg)

{

    //...

}

If the InstrumentationKey property is not supplied, it must be set through TelemetryConfiguration.Active.InstrumentationKey:

TelemetryConfiguration.Active.InstrumentationKey = "my key";

Having it as an IInterceptionBehavior should be straightforward. Feel free to modify it to your liking!

Unity, Part 10: Custom Build Strategies

Introduction

We’re getting there! This time, custom build strategies, or how you can tell Unity to build/act upon built objects in different ways.

The latest post in the series was on integration with MEF, the previous on web, before that on interfaces, even before I talked about conventions, values, extensions, Aspect-Oriented Programming, dependency injection and the first was an introduction.

Unity allows specifying custom build strategies. Depending on the stage to which they are applied, they can either build objects for us or do something upon newly built ones.

Performing Operations On Newly Built Objects

One example of the latter: suppose we wanted to implement support for ISupportInitialize (I repeat myself, I know). This is a marker interface that features two methods: BeginInit for signaling the start of the initialization process and EndInit for its end. We need a custom build strategy that knows when to call each of these methods. We add build strategies through extensions:

   1: public sealed class SupportInitializeContainerExtension : UnityContainerExtension

   2: {

   3:     protected override void Initialize()

   4:     {

   5:         var strategy = new SupportInitializeBuilderStrategy();

   6:         this.Context.Strategies.Add(strategy, UnityBuildStage.Creation);

   7:     }

   8: }

Notice how we add our build strategy to the Creation build stage. This tells Unity that the strategy’s lifecycle methods should be called before and after the object is created. It’s important to remember that only components registered with RegisterType will be intercepted, because those registered with RegisterInstance are, of course, already built.

Extensions are added to the Unity instance:

   1: unity.AddNewExtension<SupportInitializeContainerExtension>();

The build strategy itself inherits from BuilderStrategy, which in turn implements IBuilderStrategy; it’s implementation is straightforward:

   1: public sealed class SupportInitializeBuilderStrategy : BuilderStrategy

   2: {

   3:     public override void PreBuildUp(IBuilderContext context)

   4:     {

   5:         var init = context.Existing as ISupportInitialize;

   6:  

   7:         if (init != null)

   8:         {

   9:             init.BeginInit();

  10:         }

  11:  

  12:         base.PreBuildUp(context);

  13:     }

  14:  

  15:     public override void PostBuildUp(IBuilderContext context)

  16:     {

  17:         var init = context.Existing as ISupportInitialize;

  18:  

  19:         if (init != null)

  20:         {

  21:             init.EndInit();

  22:         }

  23:  

  24:         base.PostBuildUp(context);

  25:     }

  26: }

PreBuildUp and PostBuildUp are called in sequence just after the object is built (the Existing property). Other lifetime methods exist, which are called at different times, depending on which stage the builder was added to.

Overriding Object Creation

Another example would be intercepting object creation. For that we need another extension:

   1: public sealed class CustomBuildExtension : UnityContainerExtension

   2: {

   3:     public Func<Type, Type, String, MethodBase, IUnityContainer, Object> Constructor { get; set; }

   4:  

   5:     protected override void Initialize()

   6:     {

   7:         var strategy = new CustomBuilderStrategy(this);

   8:         this.Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);

   9:     }

  10: }

The Constructor delegate property takes a number of parameters and returns an object instance. These parameters are:

  • First Type: the registered type, such as ILogger;
  • Second Type: the concrete type mapped, an ILogger implementation such as ConsoleLogger;
  • String: the registered name, such as “console”, or null;
  • MethodBase: the method (or property getter/setter) where the component resolution was requested, for context;
  • IUnityContainer: the current Unity instance;

We would register it as:

   1: var extension = new CustomBuildExtension();

   2: extension.Constructor = (from, to, name, method, u) =>

   3: {

   4:     //return something

   5: };

   6:  

   7: unity.AddExtension(extension);

The strategy in this case would be like this:

   1: public sealed class CustomBuilderStrategy : BuilderStrategy

   2: {

   3:     private readonly CustomBuildExtension extension;

   4:     

   5:     public CustomBuilderStrategy(CustomBuildExtension extension)

   6:     {

   7:         this.extension = extension;

   8:     }

   9:     

  10:     private IUnityContainer GetUnityFromBuildContext(IBuilderContext context)

  11:     {

  12:         var lifetime = context.Policies.Get<ILifetimePolicy>(NamedTypeBuildKey.Make<IUnityContainer>());

  13:         return lifetime.GetValue() as IUnityContainer;

  14:     }

  15:     

  16:     public override void PreBuildUp(IBuilderContext context)

  17:     {

  18:         var stackTrace = new StackTrace();

  19:         var frame = stackTrace.GetFrame(6);

  20:         var method = frame.GetMethod();

  21:         var fromType = context.OriginalBuildKey.Type;

  22:         var name = context.OriginalBuildKey.Name;

  23:         var toType = context.BuildKey.Type;

  24:         var unity = this.GetUnityFromBuildContext(context);

  25:     

  26:         context.Existing = this.extension.Constructor(fromType, toType, name, method, unity);

  27:         context.BuildComplete = true;

  28:     

  29:         var lifetimeManager = new ContainerControlledLifetimeManager();

  30:         lifetimeManager.SetValue(context.Existing);

  31:     

  32:         context.Lifetime.Add(lifetimeManager);

  33:     

  34:         base.PreBuildUp(context);

  35:     }

  36: }

Worth mentioning:

  • A StackTrace instance is used to walk back the stack until our custom method was called;
  • The from type, name and to type are obtained from the OriginalBuildKey and BuildKey;
  • The Unity instance is a bit more tricky to get, it comes from the current Policies;
  • Existing and BuildComplete are set so that the build process is terminated with this builder;
  • The Constructor delegate is invoked and should return a proper object inheriting (or implementing) from from type;
  • A ContainerControlledLifetimeManager (aka, singleton) is used to track the new object lifetime and added to Unity’s Lifetime collection, so that when Unity is disposed of, the lifetime manager also gets disposed.

And that’s it. This way, you can decide how your object is going to be built and even on which method is it being requested. Hope you find this useful! Winking smile

Unity, Part 9: Integration With Managed Extensibility Framework

This time, I will be talking about integrating Unity with Managed Extensibility Framework (MEF). You can find the other posts in the series here (how to use Unity in a web application), here (adding Interfaces), here (registration by convention), here (injecting values), here (extensions), here (aspect-oriented programming), here (dependency injection) and the first one here (introduction).

The Managed Extensibility Framework (MEF) has been around since the release of .NET 4.0, and even before as a beta, stand-alone package. Basically, it provides an extensible mechanism for detecting and loading plugins. It’s easier to use than the similarly-named Managed Add-In Framework (MAF), and even if it’s not so feature-rich (it doesn’t support sandboxing, for once), unlike MAF, it is well alive!

So, what does MEF offer that can be of use to Unity? Well, MEF knows how to locate exports/plugins from a number of locations, like assemblies and file system directories. It’s just a matter of finding the exports we’re interested in and registering them with Unity.

An export in MEF is some class that is decorated with an ExportAttribute (technically speaking, this is just when using the Attributed Programming Model, since .NET 4.5 there is also the Convention-Based Programming Model). This attribute allows specifying the type to export (ContractType) and also the contract name (ContractName). This matches closely the Unity/IoC concept of contract type and name.

We could find all exports under a given path using MEF using an AssemblyCatalog, a particular implementation of a ComposablePartCatalog:

   1: var catalog = new AssemblyCatalog("some path");

A couple of helper functions for picking up the export’s contract type and name, by leveraging the ReflectionModelServices class:

   1: public static IDictionary<String, Type> GetExportedTypes<T>(this ComposablePartCatalog catalog)

   2: {

   3:     return (GetExportedTypes(catalog, typeof(T)));

   4: }

   5:  

   6: public static IDictionary<String, Type> GetExportedTypes(this ComposablePartCatalog catalog, Type type)

   7: {

   8:     return (catalog.Parts.Where(part => IsComposablePart(part, type) == true).ToDictionary(part => part.ExportDefinitions.First().ContractName, part => ReflectionModelServices.GetPartType(part).Value));

   9: }

  10:  

  11:  

  12: private static Boolean IsComposablePart(ComposablePartDefinition part, Type type)

  13: {

  14:     return (part.ExportDefinitions.Any(def => (def.Metadata.ContainsKey("ExportTypeIdentity") == true) && (def.Metadata["ExportTypeIdentity"].Equals(type.FullName) == true)));

  15: }

This will return a collection of key-value pairs, where the key is the contract name and the value the contract type; this is so there can be multiple contract names for a given contract type. After we have this, it’s just a matter of iterating the results and registering each occurrence:

   1: var type = typeof(ISomeType);

   2: var exports = catalog.GetExportedTypes(type);

   3:  

   4: foreach (var entry in exports)

   5: {

   6:     unity.RegisterType(type, entry.Value, entry.Key);

   7: }

So, given the following contract and implementations:

   1: public interface ISomeType

   2: {

   3:     void SomeMethod();

   4: }

   5:  

   6: [Export("Some", typeof(ISomeType))]

   7: public class SomeImplementation : ISomeType

   8: {

   9:     public void SomeMethod() { }

  10: }

  11:  

  12: [Export("Another", typeof(ISomeType))]

  13: public class AnotherImplementation : ISomeType

  14: {

  15:     public void SomeMethod() { }

  16: }

We can obtain a specific contract type implementation given it’s name:

   1: var myImplementation = unity.Resolve<ISomeType>("MyName");

And also all implementations of the contract that were found:

   1: var all = unity.ResolveAll<ISomeType>();

This can be enhanced in a couple of ways:

  • Use a Unity extension to automatically find and register exports at runtime;
  • Make use of MEF metadata to tell Unity which lifetime managers to use, and other useful properties, such as the default implementation for the contract type.

As usual, I’m looking forward for your comments!