I have two classes like:
public class P
{
public P( Guid g ) {}
}
public class Lp
{
public Lp() {}
public Lp( P p ) {}
}
I register both of them with Autofac 6.2.0 like:
builder.RegisterType< P >();
builder.RegisterType< Lp >();
Now I want to resolve an Lp using the default ctor. When I try to resolve Lp like:
var c = builder.Build();
using( var scope = c.BeginLifetimeScope() )
{
scope.Resolve<Lp>();
}
I get an error that none of the constructors found for type P
can be invoked with the available services and parameters. Well, yes, that's true.
Apparently, since type P
has been registered, Autofac thinks it should be able to create a P
and use it to create the Lp
instead of recognizing that it has no way of creating a P
without a Guid
and thus use the default Lp
ctor. If I don't register P
, the resolve succeeds. If I add a default ctor to P
, the resolve succeeds (except that it uses the non-default Lp
ctor).
The diagnostics aren't very interesting, but it looks like:
{ Resolve Request Starting {
Service: CtsMasterTs.Positions.Lp
Component: CtsMasterTs.Positions.Lp
Pipeline:
-> CircularDependencyDetectorMiddleware
-> ScopeSelectionMiddleware
-> SharingMiddleware
-> RegistrationPipelineInvokeMiddleware
-> ActivatorErrorHandlingMiddleware
-> DisposalTrackingMiddleware
-> Lp (ReflectionActivator)
Resolve Request Starting
{
Service: CtsMasterTs.Positions.P
Component: CtsMasterTs.Positions.P
Pipeline:
-> CircularDependencyDetectorMiddleware
-> ScopeSelectionMiddleware
-> SharingMiddleware
-> RegistrationPipelineInvokeMiddleware
-> ActivatorErrorHandlingMiddleware
-> DisposalTrackingMiddleware
-> P (ReflectionActivator)
X- P (ReflectionActivator)
X- DisposalTrackingMiddleware
X- ActivatorErrorHandlingMiddleware
X- RegistrationPipelineInvokeMiddleware
X- SharingMiddleware
X- ScopeSelectionMiddleware
X- CircularDependencyDetectorMiddleware
}
Resolve Request FAILED
Autofac.Core.DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'CtsMasterTs.Positions.P' can be invoked with the available services
and parameters:
Cannot resolve parameter 'System.Guid g' of constructor 'Void .ctor(System.Guid)'.
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetAllBindings(ConstructorBinder[]
availableConstructors, IComponentContext context, IEnumerable`1
parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
175
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext
context, IEnumerable`1 parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
134
at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext
ctxt, Action`1 next) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
104
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs:line
32
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs:line
36
X- Lp (ReflectionActivator)
X- DisposalTrackingMiddleware
X- ActivatorErrorHandlingMiddleware
X- RegistrationPipelineInvokeMiddleware
X- SharingMiddleware
X- ScopeSelectionMiddleware
X- CircularDependencyDetectorMiddleware } Resolve Request FAILED: Nested Resolve Failed } Operation FAILED
Autofac.Core.DependencyResolutionException: An exception was thrown
while activating CtsMasterTs.Positions.Lp -> CtsMasterTs.Positions.P.
---> Autofac.Core.DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'CtsMasterTs.Positions.P' can be invoked with the available services
and parameters: Cannot resolve parameter 'System.Guid g' of
constructor 'Void .ctor(System.Guid)'.
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetAllBindings(ConstructorBinder[]
availableConstructors, IComponentContext context, IEnumerable`1
parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
175
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext
context, IEnumerable`1 parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
134
at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext
ctxt, Action`1 next) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
104
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs:line
32
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs:line
36
--- End of inner exception stack trace ---
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs:line
48
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/SharingMiddleware.cs:line 58
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/CircularDependencyDetectorMiddleware.cs:line
94
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope
currentOperationScope, ResolveRequest request) in
/_/src/Autofac/Core/Resolving/ResolveOperation.cs:line 150
at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest
request) in /_/src/Autofac/Core/Resolving/ResolveOperation.cs:line 182
This is a problem for me, because I need to be able to create Lp
either with or without a P
. Elsewhere in the code I use injected Func<Lp>
and Func<P, Lp>
as factories. I also use injected Func<Guid, P>
to create P
objects.
So my question is - how do I either:
A) Get Autofac to look through to the P
ctor and understand that it can't use the non-default Lp
ctor without a P
parameter, OR
B) Work some Autofac magic in other ways (eg lambda registrations?) to allow Func<Lp>
and Func<P, Lp>
to both work? I've looked briefly at using ctor selection, but it seems that would force using the same ctor every time the type is resolved.
Other information -.Net Framework 4.8, VS2019, Windows 10, WPF. This is a boiled-down example that demonstrates what's happening in my (more complex) application code.
Update - Is this a code smell? I'm still trying to wrap my head around that.
The use case is that P is immutable. Lp is the "editable" version of P. When a new P is needed, I create a new Lp with the default ctor, edit the property values, and then create a P from it using Lp.CreateP(). If P already exists and needs to be edited, I create a new Lp using Lp( P i_p ), edit the property values, and then replace the original P with a new P using Lp.CreateP(). It seems reasonable to me, but maybe I'm missing something.
This is not really a common use case. The vast majority of usage would be either:
P
or don't, but not "different by context"); ORThis use case is more like... "I want to use the default Autofac behavior _except in this one nested scope where I need to override which constructor is used." I would recommend analyzing the design that necessitates this because it seems like a code smell.
However, the best you can do is to re-register Lp
in the child lifetime scope and force the constructor you want. The resolution will happen based on the override and should do what you want.
var builder = new ContainerBuilder();
builder.RegisterType<P>();
builder.RegisterType<Lp>();
var container = builder.Build();
// This will use the `Lp(P)` constructor - most matched
var first = container.Resolve<Lp>();
using(var scope = container.BeginLifetimeScope(b =>
{
b.RegisterType<Lp>().UsingConstructor(Array.Empty<Type>());
})
{
// This should use the default no-parameter constructor.
var second = scope.Resolve<Lp>();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.