列出依赖解析器 DefaultConstructorFinder 的所有缺失的 Autofac 注册
List all missing Autofac registrations for dependency resolver DefaultConstructorFinder
当 Autofac 试图通过依赖解析器解析构造函数参数时,有没有办法一次列出所有丢失的注册?或者是一次通过一个的唯一方法..
以此为例:
public MyWebApiController(IMyInterface myInterface)
我知道实现 IMyInterface 的 class MyInterfaceImpl 必须像这样用 Autofacs ContainerBuilder 注册:
builder.RegisterType<MyInterfaceImpl>().As<IMyInterface>()
但是,如果 MyInterfaceImpl 依赖于其他 10 个构造函数,并且每个构造函数都依赖于一小撮,那会怎样呢?有没有办法让 Autofac 遍历所有尚未注册到 ContainerBuilder 的依赖项,而不是抛出 DependencyResolutionException第一次出现?
取:
public MyInterfaceImpl(IMyInterface2 myInterface2, IMyInterface3 myInterface3, ... etc ...)
并且每个都有自己的构造函数需要注册..
public MyInterface2Impl(IMyInterfaceB myInterfaceB)
等等
因为我缺少 Autofac 注册,出现以下异常消息,告诉我必须注册,即 MyInterface2Impl 接口。
None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'MyWebApiController' can be invoked with the available services and
parameters
以及显示它拒绝哪个参数的详细信息:
Cannot resolve parameter 'IMyInterface2 myInterface2' of constructor
'Void .ctor(IMyInterface2 myInterface2, IMyInterface3 myInterface3,
... etc ...)
但是我可能有接下来的 5 个丢失的注册。这很烦人,因为我必须启动 site/service 并调用 api 控制器,在我修复每个丢失的注册之后,有时可能会有很多丢失的注册,在设置 coctail 时.
那么,Autofac 可以一次显示所有丢失的注册信息吗?
没有简单的方法可以做你想做的事。我检查了代码,只显示了第一个参数,见ConstructorParameterBinding.cs in github repository
for (int i = 0; i < parameters.Length; ++i)
{
var pi = parameters[i];
bool foundValue = false;
foreach (var param in availableParameters)
{
Func<object> valueRetriever;
if (param.CanSupplyValue(pi, context, out valueRetriever))
{
_valueRetrievers[i] = valueRetriever;
foundValue = true;
break;
}
}
if (!foundValue)
{
CanInstantiate = false;
_firstNonBindableParameter = pi;
break;
}
我认为这是出于性能原因。
顺便说一句,您可以使用 ResolveOperationBeginning
事件来获得您想要的特定案例。
#if DEBUG
container.ResolveOperationBeginning += (sender, e) =>
{
IComponentRegistration registration = null;
e.ResolveOperation.InstanceLookupBeginning += (sender2, e2) =>
{
registration = e2.InstanceLookup.ComponentRegistration;
};
e.ResolveOperation.CurrentOperationEnding += (sender2, e2) =>
{
if (e2.Exception != null)
{
ConstructorInfo ci = registration.Activator.LimitType
.GetConstructors()
.First();
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Can't instanciate {registration.Activator.LimitType}");
foreach (ParameterInfo pi in ci.GetParameters())
{
if (!((ILifetimeScope)sender).IsRegistered(pi.ParameterType))
{
sb.AppendLine($"\t{pi.ParameterType} {pi.Name} is not registered");
}
}
throw new DependencyResolutionException(sb.ToString(), e2.Exception);
}
};
};
#endif
它不会在所有情况下都有效,但如果你只使用构造函数注入而不使用复杂绑定,它应该足够了。
这里是完整示例:https://dotnetfiddle.net/om16sI
当 Autofac 试图通过依赖解析器解析构造函数参数时,有没有办法一次列出所有丢失的注册?或者是一次通过一个的唯一方法..
以此为例:
public MyWebApiController(IMyInterface myInterface)
我知道实现 IMyInterface 的 class MyInterfaceImpl 必须像这样用 Autofacs ContainerBuilder 注册:
builder.RegisterType<MyInterfaceImpl>().As<IMyInterface>()
但是,如果 MyInterfaceImpl 依赖于其他 10 个构造函数,并且每个构造函数都依赖于一小撮,那会怎样呢?有没有办法让 Autofac 遍历所有尚未注册到 ContainerBuilder 的依赖项,而不是抛出 DependencyResolutionException第一次出现?
取:
public MyInterfaceImpl(IMyInterface2 myInterface2, IMyInterface3 myInterface3, ... etc ...)
并且每个都有自己的构造函数需要注册..
public MyInterface2Impl(IMyInterfaceB myInterfaceB)
等等
因为我缺少 Autofac 注册,出现以下异常消息,告诉我必须注册,即 MyInterface2Impl 接口。
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyWebApiController' can be invoked with the available services and parameters
以及显示它拒绝哪个参数的详细信息:
Cannot resolve parameter 'IMyInterface2 myInterface2' of constructor 'Void .ctor(IMyInterface2 myInterface2, IMyInterface3 myInterface3, ... etc ...)
但是我可能有接下来的 5 个丢失的注册。这很烦人,因为我必须启动 site/service 并调用 api 控制器,在我修复每个丢失的注册之后,有时可能会有很多丢失的注册,在设置 coctail 时.
那么,Autofac 可以一次显示所有丢失的注册信息吗?
没有简单的方法可以做你想做的事。我检查了代码,只显示了第一个参数,见ConstructorParameterBinding.cs in github repository
for (int i = 0; i < parameters.Length; ++i)
{
var pi = parameters[i];
bool foundValue = false;
foreach (var param in availableParameters)
{
Func<object> valueRetriever;
if (param.CanSupplyValue(pi, context, out valueRetriever))
{
_valueRetrievers[i] = valueRetriever;
foundValue = true;
break;
}
}
if (!foundValue)
{
CanInstantiate = false;
_firstNonBindableParameter = pi;
break;
}
我认为这是出于性能原因。
顺便说一句,您可以使用 ResolveOperationBeginning
事件来获得您想要的特定案例。
#if DEBUG
container.ResolveOperationBeginning += (sender, e) =>
{
IComponentRegistration registration = null;
e.ResolveOperation.InstanceLookupBeginning += (sender2, e2) =>
{
registration = e2.InstanceLookup.ComponentRegistration;
};
e.ResolveOperation.CurrentOperationEnding += (sender2, e2) =>
{
if (e2.Exception != null)
{
ConstructorInfo ci = registration.Activator.LimitType
.GetConstructors()
.First();
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Can't instanciate {registration.Activator.LimitType}");
foreach (ParameterInfo pi in ci.GetParameters())
{
if (!((ILifetimeScope)sender).IsRegistered(pi.ParameterType))
{
sb.AppendLine($"\t{pi.ParameterType} {pi.Name} is not registered");
}
}
throw new DependencyResolutionException(sb.ToString(), e2.Exception);
}
};
};
#endif
它不会在所有情况下都有效,但如果你只使用构造函数注入而不使用复杂绑定,它应该足够了。
这里是完整示例:https://dotnetfiddle.net/om16sI