Click here to Skip to main content
15,896,359 members
Articles / Programming Languages / C#

Extending Unity Container to Support DefaultValue Attribute

Rate me:
Please Sign up or sign in to vote.
4.84/5 (11 votes)
3 Apr 2012CPOL4 min read 41.5K   509   19  
Extending Microsoft Enterprise Library Unity block to support custom attributes and DefaultValueAttribute in particular.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Practices.Unity;

namespace UnityDefaultValueExtension
{
    /// <summary>
    /// Extension method based implementation
    /// </summary>
    public static class AOPUnityDefaultValueExtender
    {
        /// <summary>
        /// Adds required dependency registrations required to intialize properties
        /// <param name="_this">The type.</param>
        /// <param name="injectionMembers">Other dependencies.</param>
        /// </summary>
        public static InjectionMember[] DefaultValueDependencies(this Type _this)
        {
            ArrayList defValDepends = new ArrayList();

            foreach (PropertyInfo prop in _this.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                // Skip Read Only properties
                if (!prop.CanWrite)
                    continue;

                // If DependencyAttribute is present, no need to do anything else
                if (0 < prop.GetCustomAttributes(typeof(DependencyAttribute), false).Length)
                    continue;

                // Get default attribute and register dependency
                DefaultValueAttribute[] defValue = prop.GetCustomAttributes(typeof(DefaultValueAttribute), false)
                                                                            as DefaultValueAttribute[];
                if (0 == defValue.Length)
                    continue;

                defValDepends.Add(new InjectionProperty(prop.Name,
                    (object)Convert.ChangeType(defValue[0].Value, prop.PropertyType)));
            }

            // If added any properties, merge and return
            if (0 < defValDepends.Count)
            {
                //defValDepends.InsertRange(0, );
                return (InjectionMember[])defValDepends.ToArray(typeof(InjectionMember));
            }

            return null;
        }

        /// <summary>
        /// Register Type and Interface with Unity containainer and sets up properties with
        /// DefaultValueAttribute as dependency property. Unity framework initializes these
        /// with constant value specified in the attribute.
        /// <param name="TFrom">The type.</param>
        /// <param name="TTo">A concrete mplementation of the type.</param>
        /// <param name="_this">Unity container.</param>
        /// </summary>
        public static IUnityContainer RegisterTypeWithDefaultValues<TFrom, TTo>(this IUnityContainer _this)
            where TTo : TFrom
        {
            // Register the type with the container
            return _this.RegisterType<TFrom, TTo>(typeof(TTo).DefaultValueDependencies());
        }
    }

    
    
    /// <summary>
    /// Extension initializing resolved objects with values from DefaultValueAttributes
    /// </summary>
    public class UnityDefaultValueExtender : UnityContainerExtension, IUnityDefaultValueExtender
    {
        /// <summary>
        /// Initializes this extension by attaching to registration event
        /// </summary>
        protected override void Initialize()
        {
            base.Context.Registering += new EventHandler<RegisterEventArgs>(this.OnRegister);
        }

        /// <summary>
        /// Processes registration event. Adds policies to initialize properties with constant 
        /// values retrieved from DefaultValueAttributes
        /// </summary>
        private void OnRegister(object sender, RegisterEventArgs e)
        {
            ArrayList defValDepends = new ArrayList();
            IUnityContainer container = sender as IUnityContainer;

            foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(e.TypeTo))
            {
                // Skip Read Only properties
                if (prop.IsReadOnly)
                    continue;

                // If DependencyAttribute is present, no need to do anything else
                if (null != prop.Attributes[typeof(DependencyAttribute)])
                    continue;

                // Get default attribute and register dependency
                DefaultValueAttribute defValue = prop.Attributes[typeof(DefaultValueAttribute)]
                                                                as DefaultValueAttribute;
                if (null == defValue)
                    continue;

#if LEGACY_CODE // Code for Microsoft Enterprise Libraries prior to 5 (1.2 ... 4.1)
                (new InjectionProperty(prop.DisplayName, (object)Convert.ChangeType(defValue.Value, prop.PropertyType)))
                                        .AddPolicies(e.TypeTo, e.Name, base.Context.Policies);

#else           // Code for Microsoft Enterprise Library 5.xx and up
                (new InjectionProperty(prop.DisplayName, (object)Convert.ChangeType(defValue.Value, prop.PropertyType)))
                                        .AddPolicies(e.TypeFrom, e.TypeTo, e.Name, base.Context.Policies);
#endif
            }
        }
    }



    /// <summary>
    /// Configuration Interface used to configure this extension
    /// </summary>
    public interface IUnityDefaultValueExtender : IUnityContainerExtensionConfigurator { }
}

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
Software Developer (Senior)
United States United States
Senior Software Engineer with over 20+ years of experience in variety of technologies, development tools and programming languages.

Microsoft Certified Specialist programming in C#, JavaScript, HTML, CSS

Comments and Discussions