Delegate factory throws on instance activation when it has parameter with name value
```c#
public interface ISomeService { }
public class SomeService : ISomeService { }
public class MyComponent
{
public ISomeService Service { get; set; }
public delegate MyComponent Factory(string value);
public MyComponent(string value)
{
}
}
public class ReproTest
{
[Fact]
public void Test()
{
// Arrange
var builder = new ContainerBuilder();
builder.RegisterType
builder.RegisterType
var container = builder.Build();
// Act
var factory = container.Resolve<MyComponent.Factory>();
// Assert
Assert.NotNull(factory("Autofac is great!"));
}
}
```
Delegate factory should produce properly activated component with Service property resolved.
Autofac.Core.DependencyResolutionException : An exception was thrown while activating UnitTests.MyComponent.
---- System.InvalidCastException : Unable to cast object of type 'System.String' to type 'UnitTests.ISomeService'.
Autofac: 6.2.0
What I've tried so far:
So, to work around the issue, delegate factory should not have parameter with name value.
I am able to reproduce the issue using the above code.
The full exception with stack trace is:
Autofac.Core.DependencyResolutionException: An exception was thrown while activating AutofacRepro.UnitTest1+MyComponent.
---> System.InvalidCastException: Unable to cast object of type 'System.String' to type 'ISomeService'.
at Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.CallPropertySetter[TDeclaringType,TValue](Action`2 setter, Object target, Object value)
at Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties(IComponentContext context, Object instance, IPropertySelector propertySelector, IEnumerable`1 parameters)
at Autofac.Builder.RegistrationBuilder`3.<>c__DisplayClass41_0.<PropertiesAutowired>b__0(ResolveRequestContext ctxt, Action`1 next)
at Autofac.Core.Resolving.Middleware.DelegateMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
--- End of inner exception stack trace ---
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext ctxt)
at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext ctxt)
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest request)
at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest request)
at Autofac.Core.Resolving.ResolveOperation.Execute(ResolveRequest request)
at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(ResolveRequest request)
at lambda_method(Closure , String )
at AutofacRepro.UnitTest1.Repro() in /Users/tillig/dev/autofac/_Repro/UnitTest1.cs:line 24
The exception source is actually in the property injector, and, sure enough, if you remove PropertiesAutowired then the name value doesn't matter at all. So there's something weird in the interaction of delegate factories and the property injection thing that is causing an issue.
Which makes a little more sense, as value is a reserved word when it comes to property getter/setter terminology.
I figured out the issue and laughed out loud because it totally makes sense.
In the AutoWiringPropertyInjector, each property getting autowired goes through some logic where it grabs the list of parameters available and checks to see if they can supply the instance that should be set on the property.
There are, of course, two ways a parameter can match:
value, so... any parameter that's named value will be considered a match for the property setter input.Basically, the delegate factory is passing in a named parameter value="Autofac is great!" and the property injector is like, "Oh, value is the name of the parameter to this set method, so... it matches!"
The 99.9% case is that parameters getting passed in here are _typed_ parameters, so it's safe to match like this. However, this little thing seems like a special case we'll just have to handle due to the reserved word overlap.
Most helpful comment
I figured out the issue and laughed out loud because it totally makes sense.
In the
AutoWiringPropertyInjector, each property getting autowired goes through some logic where it grabs the list of parameters available and checks to see if they can supply the instance that should be set on the property.There are, of course, two ways a parameter can match:
value, so... any parameter that's namedvaluewill be considered a match for the property setter input.Basically, the delegate factory is passing in a named parameter
value="Autofac is great!"and the property injector is like, "Oh,valueis the name of the parameter to this set method, so... it matches!"The 99.9% case is that parameters getting passed in here are _typed_ parameters, so it's safe to match like this. However, this little thing seems like a special case we'll just have to handle due to the reserved word overlap.