Skip to content

Commit 0362f7e

Browse files
authored
Merge pull request #1352 from autofac/feature/decorator-context-resolve
Make IDecoratorContext extend IComponentContext.
2 parents 3465490 + ed66591 commit 0362f7e

File tree

6 files changed

+61
-8
lines changed

6 files changed

+61
-8
lines changed

src/Autofac/Features/Decorators/DecoratorContext.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
// Copyright (c) Autofac Project. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4+
using Autofac.Core;
5+
46
namespace Autofac.Features.Decorators;
57

68
/// <summary>
79
/// Implements the decorator context, exposing the state of the decoration process.
810
/// </summary>
911
public sealed class DecoratorContext : IDecoratorContext
1012
{
13+
private readonly IComponentContext _componentContext;
14+
1115
/// <inheritdoc />
1216
public Type ImplementationType { get; private set; }
1317

@@ -23,13 +27,18 @@ public sealed class DecoratorContext : IDecoratorContext
2327
/// <inheritdoc />
2428
public object CurrentInstance { get; private set; }
2529

30+
/// <inheritdoc />
31+
public IComponentRegistry ComponentRegistry => _componentContext.ComponentRegistry;
32+
2633
private DecoratorContext(
34+
IComponentContext componentContext,
2735
Type implementationType,
2836
Type serviceType,
2937
object currentInstance,
3038
IReadOnlyList<Type>? appliedDecoratorTypes = null,
3139
IReadOnlyList<object>? appliedDecorators = null)
3240
{
41+
_componentContext = componentContext;
3342
ImplementationType = implementationType;
3443
ServiceType = serviceType;
3544
CurrentInstance = currentInstance;
@@ -40,13 +49,14 @@ private DecoratorContext(
4049
/// <summary>
4150
/// Create a new <see cref="DecoratorContext"/>.
4251
/// </summary>
52+
/// <param name="componentContext">The component context this decorator context sits in.</param>
4353
/// <param name="implementationType">The type of the concrete implementation.</param>
4454
/// <param name="serviceType">The service type being decorated.</param>
4555
/// <param name="implementationInstance">The instance of the implementation to be decorated.</param>
4656
/// <returns>A new decorator context.</returns>
47-
internal static DecoratorContext Create(Type implementationType, Type serviceType, object implementationInstance)
57+
internal static DecoratorContext Create(IComponentContext componentContext, Type implementationType, Type serviceType, object implementationInstance)
4858
{
49-
return new DecoratorContext(implementationType, serviceType, implementationInstance);
59+
return new DecoratorContext(componentContext, implementationType, serviceType, implementationInstance);
5060
}
5161

5262
/// <summary>
@@ -64,6 +74,9 @@ internal DecoratorContext UpdateContext(object decoratorInstance)
6474
appliedDecoratorTypes.AddRange(AppliedDecoratorTypes);
6575
appliedDecoratorTypes.Add(decoratorInstance.GetType());
6676

67-
return new DecoratorContext(ImplementationType, ServiceType, decoratorInstance, appliedDecoratorTypes, appliedDecorators);
77+
return new DecoratorContext(_componentContext, ImplementationType, ServiceType, decoratorInstance, appliedDecoratorTypes, appliedDecorators);
6878
}
79+
80+
/// <inheritdoc />
81+
public object ResolveComponent(ResolveRequest request) => _componentContext.ResolveComponent(request);
6982
}

src/Autofac/Features/Decorators/DecoratorMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void Execute(ResolveRequestContext context, Action<ResolveRequestContext>
6262

6363
if (context.DecoratorContext is null)
6464
{
65-
context.DecoratorContext = DecoratorContext.Create(context.Instance.GetType(), serviceType, context.Instance);
65+
context.DecoratorContext = DecoratorContext.Create(context, context.Instance.GetType(), serviceType, context.Instance);
6666
}
6767
else
6868
{

src/Autofac/Features/Decorators/IDecoratorContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Autofac.Features.Decorators;
66
/// <summary>
77
/// Defines the context interface used during the decoration process.
88
/// </summary>
9-
public interface IDecoratorContext
9+
public interface IDecoratorContext : IComponentContext
1010
{
1111
/// <summary>
1212
/// Gets the implementation type of the service that is being decorated.

test/Autofac.Specification.Test/Features/DecoratorTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Autofac Project. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4+
using Autofac.Core;
45
using Autofac.Features.Decorators;
56
using Autofac.Features.Metadata;
67
using Autofac.Features.OwnedInstances;
@@ -1252,6 +1253,40 @@ public void OpenGenericInModuleCanBeDecoratoredByDecoratorOutsideModuleWhereModu
12521253
Assert.IsType<GenericComponent<int>>(((GenericDecorator<int>)instance).Decorated);
12531254
}
12541255

1256+
[Fact]
1257+
public void DecoratorConditionalFunctionCanResolveFromContext()
1258+
{
1259+
var builder = new ContainerBuilder();
1260+
builder.RegisterInstance(new ConditionalShouldDecorate { ShouldDecorate = true });
1261+
builder.RegisterType<ImplementorA>().As<IDecoratedService>();
1262+
builder.RegisterDecorator<DecoratorA, IDecoratedService>(context => context.Resolve<ConditionalShouldDecorate>().ShouldDecorate);
1263+
1264+
var container = builder.Build();
1265+
1266+
var instance = container.Resolve<IDecoratedService>();
1267+
1268+
Assert.IsType<DecoratorA>(instance);
1269+
Assert.IsType<ImplementorA>(instance.Decorated);
1270+
}
1271+
1272+
[Fact]
1273+
public void DecoratorConditionalFunctionThrowsCircularDependencyErrorOnResolveSelf()
1274+
{
1275+
var builder = new ContainerBuilder();
1276+
builder.RegisterInstance(new ConditionalShouldDecorate { ShouldDecorate = true });
1277+
builder.RegisterType<ImplementorA>().As<IDecoratedService>();
1278+
builder.RegisterDecorator<DecoratorA, IDecoratedService>(context =>
1279+
{
1280+
// Can't do this; circular reference.
1281+
context.Resolve<IDecoratedService>();
1282+
return true;
1283+
});
1284+
1285+
var container = builder.Build();
1286+
1287+
Assert.Throws<DependencyResolutionException>(() => container.Resolve<IDecoratedService>());
1288+
}
1289+
12551290
private class MyMetadata
12561291
{
12571292
public int A { get; set; }
@@ -1457,4 +1492,9 @@ public GenericDecorator(IGenericService<T> decorated)
14571492

14581493
public IGenericService<T> Decorated { get; }
14591494
}
1495+
1496+
private class ConditionalShouldDecorate
1497+
{
1498+
public bool ShouldDecorate { get; set; }
1499+
}
14601500
}

test/Autofac.Test/Features/Decorators/DecoratorContextTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public void CreateSetsContextToPreDecoratedState()
1212
{
1313
const string implementationInstance = "Initial";
1414

15-
var context = DecoratorContext.Create(typeof(string), typeof(string), implementationInstance);
15+
var context = DecoratorContext.Create(Factory.CreateEmptyContext(), typeof(string), typeof(string), implementationInstance);
1616

1717
Assert.Equal(typeof(string), context.ServiceType);
1818
Assert.Equal(typeof(string), context.ImplementationType);
@@ -25,7 +25,7 @@ public void CreateSetsContextToPreDecoratedState()
2525
public void UpdateAddsDecoratorStateToContext()
2626
{
2727
const string implementationInstance = "Initial";
28-
var context = DecoratorContext.Create(typeof(string), typeof(string), implementationInstance);
28+
var context = DecoratorContext.Create(Factory.CreateEmptyContext(), typeof(string), typeof(string), implementationInstance);
2929

3030
const string decoratorA = "DecoratorA";
3131
context = context.UpdateContext(decoratorA);

test/Autofac.Test/Features/Decorators/DecoratorServiceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public void ConditionDefaultsToTrueWhenNotProvided()
1919
{
2020
var service = new DecoratorService(typeof(string));
2121

22-
var context = DecoratorContext.Create(typeof(string), typeof(string), "A");
22+
var context = DecoratorContext.Create(Factory.CreateEmptyContext(), typeof(string), typeof(string), "A");
2323

2424
Assert.True(service.Condition(context));
2525
}

0 commit comments

Comments
 (0)