I was trying to clean up some accessability stuff in my code, and inadvertently broke Unity dependency injection. After a while I realized that I marked some public properties t
This is my Internal Constructor Injector Extension class:
Big potential issue: 99% of this is a copy/paste of the Unity code from .NET reflector, from unity version 4.1.0.0. Newer versions of Unity may change the implementation and break this extension, or cause flakey errors. You're warned!
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.ObjectBuilder;
using Microsoft.Practices.Unity.Utility;
namespace MyApp.Unity.Configuration
{
///
/// This extension changes the behavior of Unity constructor injection to allow the use of non-public constructors.
/// By default, Unity/ObjectBuilder would call Type.GetConstructors() to get the constructors. With the default binding
/// flags, this only returns public constructors.
/// The code here is 99% copy/paste from Reflector's dissassembly of the default Unity/OB implementation.
/// My only change was to add binding flags to get all constructors, not just public ones.
/// For more info, see: Microsoft.Practices.Unity.ObjectBuilder.DefaultUnityConstructorSelectorPolicy
///
public class InternalConstructorSelectorPolicy : IConstructorSelectorPolicy
{
protected IDependencyResolverPolicy CreateResolver(ParameterInfo param)
{
List list = new List(Sequence.OfType(param.GetCustomAttributes(false)));
if (list.Count > 0)
{
return list[0].CreateResolver(param.ParameterType);
}
return new NamedTypeDependencyResolverPolicy(param.ParameterType, null);
}
private SelectedConstructor CreateSelectedConstructor(IBuilderContext context, ConstructorInfo ctor)
{
SelectedConstructor constructor = new SelectedConstructor(ctor);
foreach (ParameterInfo info in ctor.GetParameters())
{
string buildKey = Guid.NewGuid().ToString();
IDependencyResolverPolicy policy = this.CreateResolver(info);
context.PersistentPolicies.Set(policy, buildKey);
DependencyResolverTrackerPolicy.TrackKey(context.PersistentPolicies, context.BuildKey, buildKey);
constructor.AddParameterKey(buildKey);
}
return constructor;
}
private ConstructorInfo FindInjectionConstructor(Type typeToConstruct)
{
ConstructorInfo[] infoArray = Array.FindAll(typeToConstruct.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), delegate(ConstructorInfo ctor)
{
return ctor.IsDefined(typeof(InjectionConstructorAttribute), true);
});
switch (infoArray.Length)
{
case 0:
return null;
case 1:
return infoArray[0];
}
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Resources.MultipleInjectionConstructors", new object[] { typeToConstruct.Name }));
}
private ConstructorInfo FindLongestConstructor(Type typeToConstruct)
{
ConstructorInfo[] constructors = typeToConstruct.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Array.Sort(constructors, new ConstructorLengthComparer());
switch (constructors.Length)
{
case 0:
return null;
case 1:
return constructors[0];
}
int length = constructors[0].GetParameters().Length;
if (constructors[1].GetParameters().Length == length)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Resources.AmbiguousInjectionConstructor", new object[] { typeToConstruct.Name, length }));
}
return constructors[0];
}
public virtual SelectedConstructor SelectConstructor(IBuilderContext context)
{
Type typeToConstruct = BuildKey.GetType(context.BuildKey);
ConstructorInfo ctor = this.FindInjectionConstructor(typeToConstruct) ?? this.FindLongestConstructor(typeToConstruct);
if (ctor != null)
{
return this.CreateSelectedConstructor(context, ctor);
}
return null;
}
// Nested Types
private class ConstructorLengthComparer : IComparer
{
// Methods
public int Compare(ConstructorInfo x, ConstructorInfo y)
{
return (y.GetParameters().Length - x.GetParameters().Length);
}
}
}
///
/// Registeres the InternalConstructorSelectorPolicy with the Unity container.
///
public class InternalConstructorInjectionExtension : UnityContainerExtension
{
protected override void Initialize()
{
this.Context.Policies.SetDefault(typeof(IConstructorSelectorPolicy), new InternalConstructorSelectorPolicy());
}
}
}