Wrapping every resolve to a specific generic type

Dec 12, 2012 at 3:47 PM

If I have the following code

	[Serializable]
	public abstract class ValidatedCommandArgs
	{
	}

	public interface IValidatedCommand<T>
		where T : ValidatedCommandArgs
	{
		IEnumerable<ValidationError> Execute(T args);
	}

Now a simple implementation

	public class CreateClientArgs : ValidatedCommandArgs
	{
		public string Code { get; set; }
		public string Name { get; set; }
	}

	public class CreateClientCommand : IValidatedCommand<CreateClientArgs>
	{
		public IEnumerable<ValidationError> Execute(CreateClientArgs args)
		{
			throw new NotImplementedException();
		}
	}

Then register the command handler

container.RegisterType<IValidatedCommand<CreateClientArgs>>, CreateClientCommand>();

Now what I want to be able to do is to wrap every resolution of IValidatedCommand<T> so that I can essentially do this

public class LoggedCommandHandler<T> : IValidatedCommand<T>
	where T : ValidatedCommandArgs
{
	readonly IValidatedCommand<T> Inner;

	public LoggedCommandHandler(IValidatedCommand<T> inner)
	{
		this.Inner = inner;
	}

	IEnumerable<ValidationError> IValidatedCommand<T>.Execute(T args)
	{
		//Serialize ARGS
		//Save Inner.GetType().ClassName + the serialized args to the DB
		return Inner.Execute(args);
	}
}

Then whenever I resolve (for example) IValidatedCommand<CreateClientArgs> I would actually get an instance of LoggedCommandHandler<CreateClientArgs> which is resolved with inner = CreateClientCommand

Sorry for being so verbose, but I don't recall what the technique is called.

Dec 12, 2012 at 6:54 PM
Edited Dec 12, 2012 at 9:27 PM

[ANSWER REMOVED]

Dec 12, 2012 at 8:34 PM
Edited Dec 12, 2012 at 9:06 PM

mrpmorris, to quote someone: verbosity in the service of clarity is no vice.  Or maybe I just made that up?  Either way, thanks for writing a long but complete and logical question.

I'm wondering if registering open generic types can get you to where you want to go.

    var container = new UnityContainer();

    // Create named registrations mapping IValidatedCommand<*args> to the implementation for injection
    container.RegisterType(typeof(IValidatedCommand<CreateClientArgs>), typeof(CreateClientCommand), "Inner");
    container.RegisterType(typeof(IValidatedCommand<OtherClientArgs>), typeof(OtherClientCommand), "Inner");

    // register IValidatedCommand open generic type to map to LoggedCommandHandler open generic type
    // and provide injection constructor for the injection of the inner dependency
    container.RegisterType(typeof(IValidatedCommand<>), typeof(LoggedCommandHandler<>), 
        new InjectionConstructor(new ResolvedParameter(typeof(IValidatedCommand<>), "Inner")));

    var createClientCommand = container.Resolve<IValidatedCommand<CreateClientArgs>>();
    var otherClientCommand = container.Resolve<IValidatedCommand<OtherClientArgs>>();

Now whenever you ask for an IValidatedCommand<T> you will get a LoggedCommandHandler<T> with the inner constructor parameter being injected based on the specific <T> (in this case a command args) being requested.  Is this the pattern you were hoping to achieve?

Here is the full code sample (since I added some other classes for testing):

    [Serializable]
    public abstract class ValidatedCommandArgs
    {
    }

    public interface IValidatedCommand<T>
        where T : ValidatedCommandArgs
    {
        IEnumerable<ValidationError> Execute(T args);
    }

    public class CreateClientArgs : ValidatedCommandArgs
    {
        public string Code { get; set; }
        public string Name { get; set; }
    }

    public class OtherClientArgs : ValidatedCommandArgs
    {
        public Guid Id;
    }

    public class OtherClientCommand : IValidatedCommand<OtherClientArgs>
    {
        public IEnumerable<ValidationError> Execute(OtherClientArgs args)
        {
            throw new NotImplementedException();
        }
    }

    public class CreateClientCommand : IValidatedCommand<CreateClientArgs>
    {
        public IEnumerable<ValidationError> Execute(CreateClientArgs args)
        {
            throw new NotImplementedException();
        }
    }

    public class LoggedCommandHandler<T> : IValidatedCommand<T>
    where T : ValidatedCommandArgs
    {
        readonly IValidatedCommand<T> Inner;

        public LoggedCommandHandler(IValidatedCommand<T> inner)
        {
            this.Inner = inner;
        }

        IEnumerable<ValidationError> IValidatedCommand<T>.Execute(T args)
        {
            //Serialize ARGS
            //Save Inner.GetType().ClassName + the serialized args to the DB
            return Inner.Execute(args);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var container = new UnityContainer();

            // Create named registrations mapping IValidatedCommand<*args> to the implementation for injection
            container.RegisterType(typeof(IValidatedCommand<CreateClientArgs>), typeof(CreateClientCommand), "Inner");
            container.RegisterType(typeof(IValidatedCommand<OtherClientArgs>), typeof(OtherClientCommand), "Inner");

            // register IValidatedCommand open generic type to map to LoggedCommandHandler open generic type
            // and provide injection constructor for the injection of the inner dependency
            container.RegisterType(typeof(IValidatedCommand<>), typeof(LoggedCommandHandler<>), 
                new InjectionConstructor(new ResolvedParameter(typeof(IValidatedCommand<>), "Inner")));

            var createClientCommand = container.Resolve<IValidatedCommand<CreateClientArgs>>();
            var otherClientCommand = container.Resolve<IValidatedCommand<OtherClientArgs>>();
        }
    }

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Dec 12, 2012 at 9:08 PM

Note that I updated the previous code samples because LoggedCommandHandler was not being returned.  I'm now using named registrations for the inner decorators.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Dec 21, 2012 at 11:25 PM

This is the solution I went with. It needs a bit of debugging but seems to be working fine for my current needs.

http://mrpmorris.blogspot.co.uk/2012/12/decorating-unity-extension.html

Dec 24, 2012 at 5:04 AM

If you don't mind having another interface to attached the "inner", you can do away with the DecoratorTypeRegister and just have the decorator extension maintain a separate container to hold the decorators.

Switch the build stage to PostInitialization, then replace the instance using the Linq Aggregate function to build the chain from the ResolveAll result (using the IDecorator<T>.Decorate(T) method).

public interface IDecorate<T>
{
    void Decorate(T inner);
}

public class Decorating : UnityContainerExtension
{
    private IUnityContainer decoratingContainer;

    public Decorating()
    {
    }

    protected override void Initialize()
    {
        this.decoratingContainer = new UnityContainer();

        this.Context.ChildContainerCreated += Context_ChildContainerCreated;
        this.Context.Strategies.Add(
            new DecoratingBuildStrategy(this.decoratingContainer),
            UnityBuildStage.PostInitialization
            );
    }

        public IUnityContainer Decorate(Type typeToDecorate, Type decorateWith)
        {
            this.decoratingContainer.RegisterType(typeToDecorate, decorateWith, decorateWith.FullName, new TransientLifetimeManager());
            return this.Container;
        }

        public IUnityContainer Decorate<TTypeToDecorate, TDecorateWith>()
            where TDecorateWith: IDecorate<TTypeToDecorate>
        {
            return this.Decorate(typeof(TTypeToDecorate), typeof(TDecorateWith));
        }
}

internal class DecoratingBuildStrategy : BuilderStrategy
{
    readonly IUnityContainer container;

    internal DecoratingBuildStrategy(IUnityContainer container)
    {
        this.container = container;
    }

    public override void PostBuildUp(IBuilderContext context)
    {
        Type decoratorType = typeof (IDecorate<>).MakeGenericType(context.OriginalBuildKey.Type);

        object[] decorators = this.container
            .ResolveAll(context.OriginalBuildKey.Type)
            .ToArray()
            ;
        MethodInfo decorateMethod = decoratorType.GetMethod("Decorate", new Type[] {context.OriginalBuildKey.Type});

        object decorateChain = decorators.Aggregate(context.Existing, (inner, outer) =>
                                                                        {
                                                                            decorateMethod.Invoke(outer, new object[] {inner});
                                                                            return outer;
                                                                        });
        context.Existing = decorateChain;
    }
}

Dec 31, 2012 at 12:27 PM

Thanks!

I switched my original code from PreBuildup to PostBuildup as per your example and now it works perfectly :)