Skip to content

Commit

Permalink
Fixed an issue where a decorator was only applied if the decorator in…
Browse files Browse the repository at this point in the history
…terface was the first service assigned to the registration. Found while investigating #963.
  • Loading branch information
alexmg committed Mar 11, 2019
1 parent 7116bb1 commit f265d74
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 4 deletions.
9 changes: 5 additions & 4 deletions src/Autofac/Core/Registration/ComponentRegistry.cs
Expand Up @@ -260,17 +260,18 @@ public IEnumerable<IComponentRegistration> DecoratorsFor(IComponentRegistration

return _decorators.GetOrAdd(registration, r =>
{
var result = new List<IComponentRegistration>();
foreach (var service in r.Services)
{
if (service is DecoratorService || !(service is IServiceWithType swt)) continue;
var decoratorService = new DecoratorService(swt.ServiceType);
return RegistrationsFor(decoratorService)
.OrderBy(d => d.GetRegistrationOrder())
.ToArray();
var decoratorRegistrations = RegistrationsFor(decoratorService);
result.AddRange(decoratorRegistrations);
}
return Enumerable.Empty<IComponentRegistration>();
return result.OrderBy(d => d.GetRegistrationOrder()).ToArray();
});
}

Expand Down
26 changes: 26 additions & 0 deletions test/Autofac.Test/Features/Decorators/DecoratorTests.cs
Expand Up @@ -13,6 +13,10 @@ public interface IService
{
}

public interface ISomeOtherService
{
}

public interface IDecoratedService : IService
{
IDecoratedService Decorated { get; }
Expand Down Expand Up @@ -40,6 +44,11 @@ public ImplementorWithParameters(string parameter)
}
}

public class ImplementorWithSomeOtherService : IDecoratedService, ISomeOtherService
{
public IDecoratedService Decorated => this;
}

public abstract class Decorator : IDecoratedService
{
protected Decorator(IDecoratedService decorated)
Expand Down Expand Up @@ -731,5 +740,22 @@ public void DecoratorAndDecoratedBothDisposedWhenSingleInstance()
Assert.Equal(1, decorator.DisposeCallCount);
Assert.Equal(1, decorated.DisposeCallCount);
}

[Theory]
[InlineData(typeof(IDecoratedService), typeof(ISomeOtherService))]
[InlineData(typeof(ISomeOtherService), typeof(IDecoratedService))]
public void DecoratorShouldBeAppliedRegardlessOfServiceOrder(Type firstService, Type secondService)
{
var builder = new ContainerBuilder();

builder.RegisterType<ImplementorWithSomeOtherService>().As(firstService, secondService);
builder.RegisterDecorator<DecoratorA, IDecoratedService>();
var container = builder.Build();

var instance = container.Resolve<IDecoratedService>();

Assert.IsType<DecoratorA>(instance);
Assert.IsType<ImplementorWithSomeOtherService>(instance.Decorated);
}
}
}
26 changes: 26 additions & 0 deletions test/Autofac.Test/Features/Decorators/OpenGenericDecoratorTests.cs
Expand Up @@ -14,6 +14,10 @@ public interface IService<T>
{
}

public interface ISomeOtherService<T>
{
}

public interface IDecoratedService<T> : IService<T>
{
IDecoratedService<T> Decorated { get; }
Expand Down Expand Up @@ -41,6 +45,11 @@ public ImplementorWithParameters(string parameter)
}
}

public class ImplementorWithSomeOtherService<T> : IDecoratedService<T>, ISomeOtherService<T>
{
public IDecoratedService<T> Decorated => this;
}

public abstract class Decorator<T> : IDecoratedService<T>
{
protected Decorator(IDecoratedService<T> decorated)
Expand Down Expand Up @@ -658,5 +667,22 @@ public void DecoratorAndDecoratedBothDisposedWhenSingleInstance()
Assert.Equal(1, decorator.DisposeCallCount);
Assert.Equal(1, decorated.DisposeCallCount);
}

[Theory]
[InlineData(typeof(IDecoratedService<>), typeof(ISomeOtherService<>))]
[InlineData(typeof(ISomeOtherService<>), typeof(IDecoratedService<>))]
public void DecoratorShouldBeAppliedRegardlessOfServiceOrder(Type firstService, Type secondService)
{
var builder = new ContainerBuilder();

builder.RegisterGeneric(typeof(ImplementorWithSomeOtherService<>)).As(firstService, secondService);
builder.RegisterGenericDecorator(typeof(DecoratorA<>), typeof(IDecoratedService<>));
var container = builder.Build();

var instance = container.Resolve<IDecoratedService<int>>();

Assert.IsType<DecoratorA<int>>(instance);
Assert.IsType<ImplementorWithSomeOtherService<int>>(instance.Decorated);
}
}
}

0 comments on commit f265d74

Please sign in to comment.