user12285701
user12285701

Reputation:

Decorators and property injection in Autofac

I'm trying to register decorator for service these uses property injection.
When I'm adding containerBuilder.RegisterDecorator<ServiceDecorator, IService>() that properties are no longer injected.
I guess Autofac is trying to inject it to the decorator instead of original service.

I've written some tests to showcase this problem. There are services and the decorator:

public interface IService
{
    bool NestedServiceIsNotNull();
}

public interface INestedService { }

public class Service : IService
{
    public INestedService NestedService { get; set; }

    public bool NestedServiceIsNotNull()
    {
        return NestedService != null;
    }
}

public class NestedService : INestedService { }

public class ServiceDecorator : IService
{
    private readonly IService _original;

    public ServiceDecorator(IService original)
    {
        _original = original;
    }

    public bool NestedServiceIsNotNull()
    {
        return _original.NestedServiceIsNotNull();
    }
}

And the test methods:

[TestMethod]
public void PropertyInjectedServiceShouldNotBeNull()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<NestedService>().As<INestedService>();
    builder.RegisterType<Service>().As<IService>().PropertiesAutowired();
    var container = builder.Build();
    var service = container.Resolve<IService>();

    Assert.IsTrue(service.NestedServiceIsNotNull());
}

[TestMethod]
public void PropertyInjectedServiceShouldNotBeNullEvenIfDecoratorRegistered()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<NestedService>().As<INestedService>();
    builder.RegisterType<Service>().As<IService>().PropertiesAutowired();
    // Here's the difference - decorating the service
    // causes the assertion to fail.
    builder.RegisterDecorator<ServiceDecorator, IService>();
    var container = builder.Build();
    var service = container.Resolve<IService>();

    Assert.IsTrue(service.NestedServiceIsNotNull());
}

The first test passes but the second fails by assertion.

Is it correct behavior?
I'm working with a legacy project, so I shouldn't to change existing code by moving dependencies to the constructor.
Is there any way to solve this problem?

Upvotes: 3

Views: 430

Answers (1)

Travis Illig
Travis Illig

Reputation: 23894

It appears... you've found a bug! Yow! I've filed an issue on your behalf here.

All is not lost, however - you can still use decorators the way you want, you'll just have to use the older less-pretty Autofac decorator syntax to get it done.

var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();

// Decorating the service with the old syntax works.
builder.RegisterType<Service>().Named<IService>("service").PropertiesAutowired();
builder.RegisterDecorator<IService>((c, inner) => new ServiceDecorator(inner), fromKey: "service");

var container = builder.Build();
var service = container.Resolve<IService>();

Assert.True(service.NestedServiceIsNotNull());

There is more documentation on how to work with this older syntax here.

Upvotes: 1

Related Questions