Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register a decorator in autofac without manually specifying all dependencies

I have a decorator that has some other dependencies that should also be resolved using the container. Example:

public class FooDecorator : IFoo
{
    public FooDecorator(IFoo inner, IBar bar, IBaz baz)
}

I can register this like this:

builder.RegisterType<Foo>().As<IFoo>();
builder.RegisterDecorator<IFoo>((c, inner) => 
    new FooDecorator(inner, c.Resolve<IBar>(), c.Resolve<IBaz>()), "key");

This is working, however not that nice that I have to manually specify all other dependencies. What I would like to do is:

builder.RegisterDecorator<FooDecorator, IFoo>("key");

Where the IFoo is resolved to the 'inner' IFoo and the other dependencies are resolved from the container. Is this possible, or can I register a decorator with a Func that will result in this behaviour?

like image 946
Ruben Avatar asked Jun 20 '14 09:06

Ruben


2 Answers

In order to avoid specifying all dependencies manually, you should register the decorator in Autofac and resolve it inside the first parameter of the RegisterDecorator method.

builder.RegisterType<Foo>()
       .Named<IFoo>("original");
builder.RegisterType<FooDecorator>()
       .Named<IFoo>("decorator");
builder.RegisterDecorator<IFoo>((c, inner) => c.ResolveNamed<IFoo>("decorator", TypedParameter.From(inner)), "original")
       .As<IFoo>();

Registering the decorator using named registration will avoid any conflicts.

like image 129
Cyril Durand Avatar answered Sep 30 '22 21:09

Cyril Durand


Based on Ezolotko's answer, I've made an extension.

public static void RegisterDecorator<TInterface, TImplementation, TDecorator>
    (this ContainerBuilder builder) 
    where TImplementation : TInterface 
    where TDecorator : TInterface
    {
        var innerImplementationName = $"{typeof(TImplementation).Name} as implementation";
        var decoratorName = $"{typeof(TDecorator).Name} as decorator";

        builder.RegisterType<TImplementation>().Named<TInterface>(innerImplementationName);
        builder.RegisterType<TDecorator>().Named<TInterface>(decoratorName);
        builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>(decoratorName, TypedParameter.From(inner)), innerImplementationName);
    }
}

The nerd in me deeply appreciates how neatly we're all decorating each other's answers to this question about decorators.

edit

Autofac v4.9 adds a RegisterDecorator feature. Check it out, it's awesome.

like image 30
increddibelly Avatar answered Sep 30 '22 20:09

increddibelly