Click here to Skip to main content
15,897,704 members
Articles / Programming Languages / C#

Extending ObjectBuilder: Making dependancy injection inheritance aware

Rate me:
Please Sign up or sign in to vote.
4.43/5 (3 votes)
17 Jul 2008CPOL5 min read 29K   110   28  
An article on extending the dependency injection framework provided by the ObjectBuilder from the Microsoft Patterns and Practices group.
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.Practices.ObjectBuilder;
using ObjectBuilder.Extension.Properties;

namespace ObjectBuilder.Extension
{
    public class IADependencyResolver
    {
        IBuilderContext context;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="context">The builder context in which the resolver will resolve
        /// dependencies.</param>
        public IADependencyResolver(IBuilderContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            this.context = context;
        }

        /// <summary>
        /// Resolves a dependency.
        /// </summary>
        /// <param name="typeToResolve">The type to be resolved.</param>
        /// <param name="typeToCreate">
        /// The type to be created, if the type cannot be resolved (and notPresent is set to <see cref="NotPresentBehavior.CreateNew"/>).
        /// </param>
        /// <param name="id">The ID of the object to be resolved. Pass null for the unnamed object.</param>
        /// <param name="notPresent">Flag to describe how to behave if the dependency is not found.</param>
        /// <param name="searchMode">Flag to describe whether searches are local only, or local and up.</param>
        /// <returns>
        /// The dependent object. If the object is not found, and notPresent is set to <see cref="NotPresentBehavior.ReturnNull"/>, will return null.
        /// </returns>
        public object Resolve(Type typeToResolve, Type typeToCreate, string id, NotPresentBehavior notPresent, SearchMode searchMode)
        {
            if (typeToResolve == null)
                throw new ArgumentNullException("typeToResolve");
            if (!Enum.IsDefined(typeof(NotPresentBehavior), notPresent))
                throw new ArgumentException(Resources.InvalidEnumerationValue, "notPresent");

            if (typeToCreate == null)
                typeToCreate = typeToResolve;

            DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey(typeToResolve, id);

            // See if the item can be located using the DRLK...
            if (context.Locator.Contains(key, searchMode))
                return context.Locator.Get(key, searchMode);
            // When injecting items with the DependencyAttribute it doesn't take into account implemented interfaces.
            // This code fixes that behaviour.
            else if (!string.IsNullOrEmpty(id))
            {
                // See if we can find the item requested
                object retVal = ResolveBasedOnId(typeToResolve, id, searchMode);
                // If we've found the item requested, return it
                if (retVal != null) return retVal;
            }

            switch (notPresent)
            {
                case NotPresentBehavior.CreateNew:
                    return context.HeadOfChain.BuildUp(context, typeToCreate, null, key.ID);

                case NotPresentBehavior.ReturnNull:
                    return null;

                default:
                    throw new DependencyMissingException(string.Format(CultureInfo.CurrentCulture, Resources.DependencyMissing, typeToResolve.ToString()));
            }
        }

        /// <summary>
        /// Resolves the item based on id.
        /// </summary>
        /// <param name="typeToResolve">The type to resolve.</param>
        /// <param name="id">The id.</param>
        /// <param name="searchMode">The search mode.</param>
        /// <returns></returns>
        private object ResolveBasedOnId(Type typeToResolve, string id, SearchMode searchMode)
        {
            IReadableLocator locator = context.Locator;
            object retVal = null;

            // This loop is for if we're going up the parents of the list
            while ((retVal == null) && (locator != null))
            {
                // Go through all the items in the locator
                foreach (KeyValuePair<object, object> pair in locator)
                {
                    // We're only interested in things that have a DependencyResolutionLocatorKey key
                    if (pair.Key is DependencyResolutionLocatorKey)
                    {
                        DependencyResolutionLocatorKey depKey = (DependencyResolutionLocatorKey)pair.Key;

                        // See if the key's id and the id we're looking for match
                        if (object.Equals(depKey.ID, id))
                            retVal = IsResolvable(pair.Value, typeToResolve);
                    }

                    // Do a check to see if we've found our object (no point carrying on if we have!)
                    if (retVal != null) return retVal;
                }

                // See if we need to go up to the parent. This is done under the following conditions:
                //      - searchMode has been set to up
                if (searchMode == SearchMode.Up)
                    locator = locator.ParentLocator;
                else
                    locator = null;
            }

            // Return whatever we have (or haven't) found
            return retVal;
        }

        /// <summary>
        /// Determines whether the specified object is resolvable to the specified type.
        /// </summary>
        /// <param name="Test">The object to test.</param>
        /// <param name="typeToResolve">The type to resolve.</param>
        /// <returns><c>Test</c> if the object is resolvable; otherwise <c>null</c>.</returns>
        private object IsResolvable(object Test, Type typeToResolve)
        {
            if (typeToResolve.IsAssignableFrom(Test.GetType()))
                return Test;
            else
                return null;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions