Показаны сообщения с ярлыком Unity. Показать все сообщения
Показаны сообщения с ярлыком Unity. Показать все сообщения

вторник, 5 октября 2010 г.

Introducing UStatic: check Unity injection statically

A few months ago I’ve made post about wrapper over Unity container that allows to verify object structure during compilation. At that time this wrapper supports only one type of injection – through properties (setter injection). Today it evolve into more evil and aggressive creature that besides property injection can initialize objects through calling specified constructors (constructor injection) and invoking methods.

Basically idea remains the same: we use lambdas for collecting user-defined configuration and describe dependencies as expression trees (amazing stuff, BTW! it can be applied to solve dozens of problems, from describing queries to being source for automatic generation of WPF ViewModels). With properties everything is pretty trivial:

using System;
using Microsoft.Practices.Unity;
using UStatic;

namespace UStaticTest
{
class Program
{
static void Main()
{
var container = new UnityContainer();

container.RegisterType<AnotherTestObject>(
c => c
.SetName("Test1")
.SetValueProperty(_ => _.Name, "The one you need")
);

container.RegisterType<AnotherTestObject>(
c => c
.SetValueProperty(_ => _.Name, "How did you get it??")
);

container.RegisterType<TestObject>(
c => c
.SetResolvedProperty(_ => _.A, "Test1")
.SetValueProperty(_ => _.B, "String value")
);

var testObject = container.Resolve<TestObject>();
Console.WriteLine(testObject.A.Name); // The one you need
Console.WriteLine(testObject.B); // String value
}
}

class TestObject
{
public AnotherTestObject A { get; set; }
public string B { get; set; }
}

public class AnotherTestObject
{
public string Name { get; set; }
}
}

We register AnotherTestObject twice: first time with name and  second – anonymous. For both registrations we specify value being set into property Name. After that we register TestObject with resolved property A. Our extension translates expression trees into various subtypes of InjectionMember but preserving type related information. This is funny but not new, we have already seen it in the previous post. What is really interesting is how can we use expression trees to describe constructor and method call. If we want to pass constant values everything is straightforward – just make another method in the interface, name it SetInitMethod and analyze expression in the similar way with SetResolvedProperty. But was if we want method arguments to be resolved from container during instance initialization? This is usual and widely used scenario. We need some auxiliary types to denote holes in our source expression so later this holes can be filled using values from container.

    /// <summary>
/// This type is used to make typed placeholders in expression trees that will be filled with actual values during resolution.
/// </summary>
public static class Param
{
internal static readonly MethodInfo ResolvedMethod = new Func<ResolvedParameterPlaceholder<int>>(Resolved<int>).Method.GetGenericMethodDefinition();
internal static readonly MethodInfo ResolvedWithNameMethod = new Func<string, ResolvedParameterPlaceholder<int>>(Resolved<int>).Method.GetGenericMethodDefinition();

public sealed class ResolvedParameterPlaceholder<T>
{
private ResolvedParameterPlaceholder() { }

public static implicit operator T(ResolvedParameterPlaceholder<T> p)
{
throw NoDynamicInvokation();
}
}

/// <summary>
/// Denotes placeholder for resolved value with specified type.
/// </summary>
/// <typeparam name="T">Type of target object</typeparam>
/// <returns>Resolution placeholder</returns>
public static ResolvedParameterPlaceholder<T> Resolved<T>()
{
throw NoDynamicInvokation();
}

/// <summary>
/// Denotes placeholder for resolved value with specified type and name.
/// </summary>
/// <typeparam name="T">Type of target object</typeparam>
/// <param name="name">Name of target object</param>
/// <returns>Resolution placeholder</returns>
public static ResolvedParameterPlaceholder<T> Resolved<T>(string name)
{
throw NoDynamicInvokation();
}

private static Exception NoDynamicInvokation()
{
return new InvalidOperationException("This operation is intended to be used in expression trees only");
}
}

ResolvedParameterPlaceholder type will act as placeholder (that’s why he has such weird name). It shouldn’t ever be created, we intended to use it only as marker in expression trees. Implicit conversion operator allows to use this type instead of any other actual types. Our analyzer will process usages of Param.Resolved separately and use ResolvedParameter instead of value. Nice and simple idea and it should also work for constructors. To select constructor we will use new expression + direct values and Param.Resolved.

using System;
using Microsoft.Practices.Unity;
using UStatic;

namespace UStaticTest
{
class Program
{
static void Main()
{
var container = new UnityContainer();

container.RegisterType<AnotherTestObject>(
c => c
.SetValueProperty(_ => _.Name, "AnotherTestObject")
);
container.RegisterType<YetAnotherTestObject>(
c => c
.SetValueProperty(_ => _.Name, "YetAnotherTestObject")
);

container.RegisterType<TestObject>(
c => c
.SetConstructor(() => new TestObject(Param.Resolved<YetAnotherTestObject>()))
.SetInitMethod(_ => _.Initialize(Param.Resolved<AnotherTestObject>()))
);

container.Resolve<TestObject>(); // Initialize: testObject.Name = AnotherTestObject, B = YetAnotherTestObject
}
}

class TestObject
{
public TestObject(YetAnotherTestObject obj)
{
B = obj;
}

public TestObject(YetAnotherTestObject obj, string text)
{
throw new InvalidOperationException("What's happen??");
}

public YetAnotherTestObject B { get; set; }

public void Initialize(AnotherTestObject testObject)
{
Console.WriteLine("Initialize: testObject.Name = {0}, B = {1}", testObject.Name, B.Name);
}
}

public class AnotherTestObject
{
public string Name { get; set; }
}

public class YetAnotherTestObject
{
public string Name { get; set; }
}
}

Complete source code of this project(I’ve named it UStatic) is avaiable here. As always any suggestions, constructive critisicm (and especially huge money donations :) ) are welcomed and appreciated.

воскресенье, 21 февраля 2010 г.

Extending Unity configuration.

For the first time I’ve used DI container 5 years ago (it was Spring for Java). During the first experience I was greatly impressed with the required style of design: component needs to do only what outer world expect from him. All other things, like creating or locating dependencies should be put outside the component. This is quite obvious but abidance of these simple rules brings a number of valuable benefits:

  • If component does only what it is responsible to do then the code decreases in size and become easier to understand
  • All dependencies of component can be determined from its public interface (through properties, constructor parameters etc)
  • Level of potential reusability increases due to low coupling
  • Testability increases especially with application of tools like RhinoMocks and Moq

Unity is a simple and lightweight DI container for .NET. It allows defining interconnections between components both in XML and using API of IUnityContainer. In this post I’d like to show the idea how configuration mechanism can be extended using possibilities of C# 3.0.

Sample classes and interfaces:
public interface IMyComponent
{
void Run();
}

public interface ILogger
{
void LogInfo(string format, params object[] args);
}


public class MyComponent : IMyComponent
{
public string Text { get; set; }
public ILogger Logger { get; set; }
public void Run()
{
Logger.LogInfo(Text);
}
}

public class ConsoleLogger : ILogger
{
public void LogInfo(string format, params object[] args)
{
Console.WriteLine(format, args);
}
}

As we can see MyComponent class is decoupled from concrete implementation of ILogger so is can be tested with ILogger stub, reused with other type of logger and so on. Let’s create a code that will wire up all these components together.

1. Create UnityContainer and register all types in it

var container = new UnityContainer()
.RegisterType<IMyComponent, MyComponent>(
new InjectionMember[]
{
new InjectionProperty("Logger", new ResolvedParameter(typeof (ILogger),"Logger")),
new InjectionProperty("Text", "DataSource=...")
}
)
.RegisterType<ILogger, ConsoleLogger>("Logger");

For this sample I've used beta release of Unity – Feb 2010, in the older versions configuration of injected members is available only through calling ConfigureInjectionFor with InjectedMembers extension.

2. Instantiate MyComponent and run operation

var myComponent = container.Resolve<IMyComponent>();
myComponent.Run();

Line "DataSource=…" should appear in console.

Everything seems to be fine, but… IMHO this version of code has few flaws. First: property is referred via string name and this is very error prone. One occasional rename operation and BOOM!!! Second inconvenience is that property type should be set explicitly. This is annoying and unsafe approach, developer can change type of property but DI container will still try to inject dependent object relying on the old type. Let's add that both of mentioned errors are invisible to compiler and reveal itself only in runtime.

Time to make some improvements. C# 3.0 already provides ways to refer type members in type-safe way via using expression trees. We can apply them both to define target property and to get its type. This version will be much more resistant to errors because of compiler control.

In the beginning - some auxiliary types

/// <summary>
/// Accumulator of type-related settings
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ITypeConfigurator<T>
{
ITypeConfigurator<T> SetName(string name);
ITypeConfigurator<T> SetLifetimeManager(LifetimeManager lifetimeManager);
ITypeConfigurator<T> SetResolvedProperty<TRes>(Expression<Func<T, TRes>> expr);
ITypeConfigurator<T> SetResolvedProperty<TRes>(Expression<Func<T, TRes>> expr, string objectName);
ITypeConfigurator<T> SetValueProperty<TRes>(Expression<Func<T, TRes>> expr, TRes value);
}

public class TypeConfigurator<T> : ITypeConfigurator<T>
{
public TypeConfigurator()
{
InjectionMembers = new List<InjectionMember>();
LifetimeManager = new ContainerControlledLifetimeManager(); // default value
}

public string Name { get; private set; }
public LifetimeManager LifetimeManager { get; private set; }
public List<InjectionMember> InjectionMembers { get; private set; }

ITypeConfigurator<T> ITypeConfigurator<T>.SetName(string name)
{
Name = name;
return this;
}

ITypeConfigurator<T> ITypeConfigurator<T>.SetLifetimeManager(LifetimeManager lifetimeManager)
{
LifetimeManager = lifetimeManager;
return this;
}

ITypeConfigurator<T> ITypeConfigurator<T>.SetResolvedProperty<TRes>(Expression<Func<T, TRes>> expr)
{
return AddResolvedProperty(expr, null);
}

ITypeConfigurator<T> ITypeConfigurator<T>.SetResolvedProperty<TRes>(Expression<Func<T, TRes>> expr, string objectName)
{
return AddResolvedProperty(expr, objectName);
}

private ITypeConfigurator<T> AddResolvedProperty<TRes>(Expression<Func<T, TRes>> expr, string objectName)
{
var property = GetPropertyInfo(expr);
var propertyValue = string.IsNullOrEmpty(objectName)
? new ResolvedParameter<TRes>()
: new ResolvedParameter<TRes>(objectName);
InjectionMembers.Add(new InjectionProperty(property.Name, propertyValue));
return this;
}

ITypeConfigurator<T> ITypeConfigurator<T>.SetValueProperty<TRes>(Expression<Func<T, TRes>> expr, TRes value)
{
var property = GetPropertyInfo(expr);
InjectionMembers.Add(new InjectionProperty(property.Name, value));
return this;
}

private static PropertyInfo GetPropertyInfo(LambdaExpression expr)
{
var memberExpression = expr.Body as MemberExpression;
if (memberExpression == null)
throw new ArgumentException("Simple member expression expected");

var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("Property access expression expected");
return propertyInfo;
}
}

Entry point to improved configuration mechanism can be defined as an extension method for IUnityContainer interface.

public static class UnityContainerExtensions
{
/// <summary>
/// Gathers type information and applies it to provided container.
/// </summary>
/// <remarks>
/// I have used delegate <see cref="configurator"/> in interface for simplification
/// because otherwise I need to create bunch of overloads
/// RegisterType(name, SetLifetimeManager...)
/// RegisterType(name, ...)
/// RegisterType(...)
/// RegisterType(SetLifetimeManager)
/// In current version in case of need it is possible to set SetLifetimeManager and SetName with <see cref="ITypeConfigurator{T}.SetName"/>
/// or <see cref="ITypeConfigurator{T}.SetLifetimeManager"/> methods.
/// </remarks>
public static IUnityContainer RegisterType<TFrom, TTo>(
this IUnityContainer container,
Action<ITypeConfigurator<TTo>> configurator
) where TTo : TFrom
{
var typeConfigurator = new TypeConfigurator<TTo>();
// configurator will accumulate all settings defined by user
configurator(typeConfigurator);

// collected settings are applied to actual container
return container.RegisterType<TFrom, TTo>(
typeConfigurator.Name,
typeConfigurator.LifetimeManager,
typeConfigurator.InjectionMembers.ToArray()
);
}
}

And finally, advanced configurator in action:

var container = new UnityContainer()
.RegisterType<IMyComponent, MyComponent>(
c =>
c
.SetResolvedProperty(_ => _.Logger, "Logger")
.SetValueProperty(_ => _.Text, "DataSource=..")
)
.RegisterType<ILogger, ConsoleLogger>("Logger");

var myComponent = container.Resolve<IMyComponent>();
myComponent.Run();


Summary: unnecesary stuff removed, error-resistance: +10, additional skills: compile-time checks over property names, automatic inference of property types

 
GeekySpeaky: Submit Your Site!