属性 注入的 DryIOC 容器配置
DryIOC Container configuration for property injection
我广泛搜索了一个简单示例,说明如何配置 DryIoc 容器以简单地将依赖项作为属性注入,就像注入构造函数参数一样。
给定以下工作示例...
容器注册:
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
小部件服务:
public class WidgetService : IWidgetService
{
private readonly IWidgetRepository _widgetRepository;
public WidgetService(IWidgetRepository widgetRepository)
{
_widgetRepository = widgetRepository;
}
public IList<Widget> GetWidgets()
{
return _widgetRepository.GetWidgets().ToList();
}
}
小部件存储库:
public class WidgetRepository : IWidgetRepository
{
private readonly IList<Widget> _widgets;
public WidgetRepository()
{
_widgets = new List<Widget>
{
new Widget {Name = "Widget 1", Cost = new decimal(1.99), Description = "The first widget"},
new Widget {Name = "Widget 2", Cost = new decimal(2.99), Description = "The second widget"}
};
}
public IEnumerable<Widget> GetWidgets()
{
return _widgets.AsEnumerable();
}
}
需要如何更改配置以支持 DryIoc 将 WidgetRepository 作为 属性 注入的 WidgetService?
所需的小部件服务:
public class WidgetService : IWidgetService
{
public IWidgetRepository WidgetRepository { get; set; }
public IList<Widget> GetWidgets()
{
return WidgetRepository.GetWidgets().ToList();
}
}
失败尝试
我已经尝试了这些配置更改,但它们似乎无法在 WidgetService 上启用 属性 注入。
尝试 1:
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
// Seems logical - no luck
c.InjectPropertiesAndFields(PropertiesAndFields.Auto);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
尝试 2:
public static void Register(HttpConfiguration config)
{
var c = new Container(Rules.Default.With(propertiesAndFields: PropertiesAndFields.Auto))
.WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
我也用 PropertiesAndFields.All
尝试过上述方法,同样没有成功。
注意:我知道 属性 注入不是推荐的方法,构造函数注入是首选,原因有很多。但是,我想知道如何正确地做到这两点。
更新
按照@dadhi 的建议,我更改了尝试 #2 来初始化容器,例如:
var c = new Container(Rules.Default.With(propertiesAndFields: PropertiesAndFields.All(withNonPublic: false,
withPrimitive: false,
withFields: false,
ifUnresolved: IfUnresolved.Throw)))
.WithWebApi(config);
但后来我收到了这个错误:
{
"Message" : "An error has occurred.",
"ExceptionMessage" : "An error occurred when trying to create a controller of type 'WidgetController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType" : "System.InvalidOperationException",
"StackTrace" : " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException" : {
"Message" : "An error has occurred.",
"ExceptionMessage" : "Type 'IOCContainerTest.DryIOC.Controllers.WidgetController' does not have a default constructor",
"ExceptionType" : "System.ArgumentException",
"StackTrace" : " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
DryIoc 现在似乎正在尝试使用我没有的无参数构造函数来初始化我的 WidgetController。我假设由于规则更改为 PropertiesAndFields.All(...)
,DryIoc 正在尝试对所有已注册项目使用 属性 注入。
public class WidgetController : ApiController
{
private readonly IWidgetService _widgetService;
public WidgetController(IWidgetService widgetService)
{
_widgetService = widgetService;
}
// GET api/<controller>
public List<WidgetSummary> Get()
{
return _widgetService.GetWidgetSummaries();
}
}
我试图使用 属性 注入来初始化 WidgetService(如上所示),但 WidgetController 使用构造函数注入。也许我不能两者都做,但我认为 PropertiesAndFields.Auto
规则会允许两者都做。我也更改了 WidgetController 以设置为 属性 注入。然后我没有从 DryIoc 获得异常,但 WidgetService 在 WidgetController 中最终为 null。这是更新后的 WidgetController。
public class WidgetController : ApiController
{
public IWidgetService WidgetService { get; set; }
// GET api/<controller>
public List<WidgetSummary> Get()
{
return WidgetService.GetWidgetSummaries();
}
}
自动 属性 注入似乎仍然难以捉摸。
更新 2
经过反复试验(以及@dadhi 的建议),我决定在我的 WidgetController 中使用构造函数注入,并在注册其他服务时指定 属性 注入。这允许将现在使用 属性 注入的代码随着时间的推移迁移到构造函数注入,但控制器除外。这是我更新的容器注册:
public static void Register(HttpConfiguration config)
{
var c = new Container(Rules.Default).WithWebApi(config);
var autoInjectProps = Made.Of(propertiesAndFields: PropertiesAndFields.Auto);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton, autoInjectProps);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton, autoInjectProps);
}
我很想最终找出适用于控制器和其他服务的黄金设置,但它们的行为似乎有所不同。但是,目前这是一个足够可行的解决方案。
更新 3
根据@dadhi 的建议将容器配置更新为以下内容,以尝试将所有内容(包括 WidgetController)连接为 属性 注入:
public static void Register(HttpConfiguration config)
{
var c = new Container(Rules.Default.With(propertiesAndFields: PropertiesAndFields.All(withNonPublic: false, withPrimitive: false, withFields: false, ifUnresolved: IfUnresolved.Throw)))
.WithWebApi(config, throwIfUnresolved: type => type.IsController());
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
这似乎至少产生了一个有意义的异常,也许可以解释为什么当我将容器设置为使用 PropertiesAndFields.All(..)
:
{
"Message" : "An error has occurred.",
"ExceptionMessage" : "An error occurred when trying to create a controller of type 'WidgetController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType" : "System.InvalidOperationException",
"StackTrace" : " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException" : {
"Message" : "An error has occurred.",
"ExceptionMessage" : "Unable to resolve HttpConfiguration as property \"Configuration\"\r\n in IOCContainerTest.DryIOC.Controllers.WidgetController.\r\nWhere no service registrations found\r\n and number of Rules.FallbackContainers: 0\r\n and number of Rules.UnknownServiceResolvers: 0",
"ExceptionType" : "DryIoc.ContainerException",
"StackTrace" : " at DryIoc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object arg3)\r\n at DryIoc.Container.ThrowUnableToResolve(Request request)\r\n at DryIoc.Container.DryIoc.IContainer.ResolveFactory(Request request)\r\n at DryIoc.ReflectionFactory.InitPropertiesAndFields(NewExpression newServiceExpr, Request request)\r\n at DryIoc.ReflectionFactory.CreateExpressionOrDefault(Request request)\r\n at DryIoc.Factory.GetExpressionOrDefault(Request request)\r\n at DryIoc.Factory.GetDelegateOrDefault(Request request)\r\n at DryIoc.Container.ResolveAndCacheDefaultDelegate(Type serviceType, Boolean ifUnresolvedReturnDefault, IScope scope)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
第一次尝试应该改为:
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
// Resolve service first then inject properties into it.
var ws = c.Resolve<IWidgetService>();
c.InjectPropertiesAndFields(ws);
}
仅从代码进行的第二次尝试应该可以,但也可能是其他原因。要找出答案,您可以将规则更改为:
PropertiesAndFields.All(withNonPublic: false, withPrimitives: false, withFields: false, ifUnresolved: IfUnresolved.Throw)
不过,更好的选择是为精确服务指定精确 属性:
c.Register<IWidgetService, WidgetService>(Reuse.Singleton,
made: PropertiesAndFields.Of.Name("WidgetRepository"));
或强类型:
c.Register<IWidgetService, WidgetService>(
Made.Of(() => new WidgetService { WidgetRepository = Arg.Of<IWidgetRepository>() }),
Reuse.Singleton);
更新:
DryIoc 设计时采用了最不意外的默认设置:类型为 DI 的单个构造函数且没有 属性 注入。但是您可以选择默认值以简化迁移:
IContainer c = new Container(Rules.Default.With(
FactoryMethod.ConstructorWithResolvableArguments,
propertiesAndFields: PropertiesAndFilds.Auto);
对于你的情况来说可能就足够了。
如果没有,您可以添加规则:
.WithFactorySelector(Rules.SelectLastRegisteredFactory())
.WithTrackingDisposableTransients()
.WithAutoConcreteTypeResolution()
更新 2:
这个测试对我有用。
[Test]
public void Controller_with_property_injection()
{
var config = new HttpConfiguration();
var c = new Container()
.With(rules => rules.With(propertiesAndFields: PropertiesAndFields.Auto))
.WithWebApi(config, throwIfUnresolved: type => type.IsController());
c.Register<A>(Reuse.Singleton);
using (var scope = config.DependencyResolver.BeginScope())
{
var propController = (PropController)scope.GetService(typeof(PropController));
Assert.IsNotNull(propController.A);
}
}
public class PropController : ApiController
{
public A A { get; set; }
}
public class A {}
但将PropertiesAndFields.Auto
改为
PropertiesAndFields.All(false, false, false, IfUnresolved.Throw)
产生了更新 3 的错误。
更新 3:
感谢您上传 sample repo,它有助于找到问题。
DryIoc PropertiesAndFields.Auto
规则将注入所有声明的和 base class 属性,这会导致 base ApiController
中定义的某些属性出错class。好处是 Auto
只是一个预定义规则,您可以定义自己的规则以排除基础 class 属性:
private static IEnumerable<PropertyOrFieldServiceInfo> DeclaredPublicProperties(Request request)
{
return (request.ImplementationType ?? request.ServiceType).GetTypeInfo()
.DeclaredProperties.Where(p => p.IsInjectable())
.Select(PropertyOrFieldServiceInfo.Of);
}
然后像这样创建容器:
var c = new Container()
.With(rules => rules.With(propertiesAndFields: DeclaredPublicProperties))
.WithWebApi(config, throwIfUnresolved: type => type.IsController());
我已经提交了 PR 和修复。
BTW 在未来/下一个 DryIoc 版本中,我将提供 API 来简化基础或仅声明 属性 选择。
好的,忽略我最后的评论,可能不相关。查看异常堆栈跟踪,WebAPI 似乎回退到对控制器使用 Activator.CreateInstance,那是因为 DryIoc 无法解析它。但是回退掩盖了实际的 DryIoc 错误。要找出答案,请尝试:
container.WithWebApi(throwIfUnresolved: type => type.IsController());
我广泛搜索了一个简单示例,说明如何配置 DryIoc 容器以简单地将依赖项作为属性注入,就像注入构造函数参数一样。
给定以下工作示例...
容器注册:
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
小部件服务:
public class WidgetService : IWidgetService
{
private readonly IWidgetRepository _widgetRepository;
public WidgetService(IWidgetRepository widgetRepository)
{
_widgetRepository = widgetRepository;
}
public IList<Widget> GetWidgets()
{
return _widgetRepository.GetWidgets().ToList();
}
}
小部件存储库:
public class WidgetRepository : IWidgetRepository
{
private readonly IList<Widget> _widgets;
public WidgetRepository()
{
_widgets = new List<Widget>
{
new Widget {Name = "Widget 1", Cost = new decimal(1.99), Description = "The first widget"},
new Widget {Name = "Widget 2", Cost = new decimal(2.99), Description = "The second widget"}
};
}
public IEnumerable<Widget> GetWidgets()
{
return _widgets.AsEnumerable();
}
}
需要如何更改配置以支持 DryIoc 将 WidgetRepository 作为 属性 注入的 WidgetService?
所需的小部件服务:
public class WidgetService : IWidgetService
{
public IWidgetRepository WidgetRepository { get; set; }
public IList<Widget> GetWidgets()
{
return WidgetRepository.GetWidgets().ToList();
}
}
失败尝试
我已经尝试了这些配置更改,但它们似乎无法在 WidgetService 上启用 属性 注入。
尝试 1:
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
// Seems logical - no luck
c.InjectPropertiesAndFields(PropertiesAndFields.Auto);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
尝试 2:
public static void Register(HttpConfiguration config)
{
var c = new Container(Rules.Default.With(propertiesAndFields: PropertiesAndFields.Auto))
.WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
我也用 PropertiesAndFields.All
尝试过上述方法,同样没有成功。
注意:我知道 属性 注入不是推荐的方法,构造函数注入是首选,原因有很多。但是,我想知道如何正确地做到这两点。
更新
按照@dadhi 的建议,我更改了尝试 #2 来初始化容器,例如:
var c = new Container(Rules.Default.With(propertiesAndFields: PropertiesAndFields.All(withNonPublic: false,
withPrimitive: false,
withFields: false,
ifUnresolved: IfUnresolved.Throw)))
.WithWebApi(config);
但后来我收到了这个错误:
{
"Message" : "An error has occurred.",
"ExceptionMessage" : "An error occurred when trying to create a controller of type 'WidgetController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType" : "System.InvalidOperationException",
"StackTrace" : " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException" : {
"Message" : "An error has occurred.",
"ExceptionMessage" : "Type 'IOCContainerTest.DryIOC.Controllers.WidgetController' does not have a default constructor",
"ExceptionType" : "System.ArgumentException",
"StackTrace" : " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
DryIoc 现在似乎正在尝试使用我没有的无参数构造函数来初始化我的 WidgetController。我假设由于规则更改为 PropertiesAndFields.All(...)
,DryIoc 正在尝试对所有已注册项目使用 属性 注入。
public class WidgetController : ApiController
{
private readonly IWidgetService _widgetService;
public WidgetController(IWidgetService widgetService)
{
_widgetService = widgetService;
}
// GET api/<controller>
public List<WidgetSummary> Get()
{
return _widgetService.GetWidgetSummaries();
}
}
我试图使用 属性 注入来初始化 WidgetService(如上所示),但 WidgetController 使用构造函数注入。也许我不能两者都做,但我认为 PropertiesAndFields.Auto
规则会允许两者都做。我也更改了 WidgetController 以设置为 属性 注入。然后我没有从 DryIoc 获得异常,但 WidgetService 在 WidgetController 中最终为 null。这是更新后的 WidgetController。
public class WidgetController : ApiController
{
public IWidgetService WidgetService { get; set; }
// GET api/<controller>
public List<WidgetSummary> Get()
{
return WidgetService.GetWidgetSummaries();
}
}
自动 属性 注入似乎仍然难以捉摸。
更新 2
经过反复试验(以及@dadhi 的建议),我决定在我的 WidgetController 中使用构造函数注入,并在注册其他服务时指定 属性 注入。这允许将现在使用 属性 注入的代码随着时间的推移迁移到构造函数注入,但控制器除外。这是我更新的容器注册:
public static void Register(HttpConfiguration config)
{
var c = new Container(Rules.Default).WithWebApi(config);
var autoInjectProps = Made.Of(propertiesAndFields: PropertiesAndFields.Auto);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton, autoInjectProps);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton, autoInjectProps);
}
我很想最终找出适用于控制器和其他服务的黄金设置,但它们的行为似乎有所不同。但是,目前这是一个足够可行的解决方案。
更新 3
根据@dadhi 的建议将容器配置更新为以下内容,以尝试将所有内容(包括 WidgetController)连接为 属性 注入:
public static void Register(HttpConfiguration config)
{
var c = new Container(Rules.Default.With(propertiesAndFields: PropertiesAndFields.All(withNonPublic: false, withPrimitive: false, withFields: false, ifUnresolved: IfUnresolved.Throw)))
.WithWebApi(config, throwIfUnresolved: type => type.IsController());
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
这似乎至少产生了一个有意义的异常,也许可以解释为什么当我将容器设置为使用 PropertiesAndFields.All(..)
:
{
"Message" : "An error has occurred.",
"ExceptionMessage" : "An error occurred when trying to create a controller of type 'WidgetController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType" : "System.InvalidOperationException",
"StackTrace" : " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException" : {
"Message" : "An error has occurred.",
"ExceptionMessage" : "Unable to resolve HttpConfiguration as property \"Configuration\"\r\n in IOCContainerTest.DryIOC.Controllers.WidgetController.\r\nWhere no service registrations found\r\n and number of Rules.FallbackContainers: 0\r\n and number of Rules.UnknownServiceResolvers: 0",
"ExceptionType" : "DryIoc.ContainerException",
"StackTrace" : " at DryIoc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object arg3)\r\n at DryIoc.Container.ThrowUnableToResolve(Request request)\r\n at DryIoc.Container.DryIoc.IContainer.ResolveFactory(Request request)\r\n at DryIoc.ReflectionFactory.InitPropertiesAndFields(NewExpression newServiceExpr, Request request)\r\n at DryIoc.ReflectionFactory.CreateExpressionOrDefault(Request request)\r\n at DryIoc.Factory.GetExpressionOrDefault(Request request)\r\n at DryIoc.Factory.GetDelegateOrDefault(Request request)\r\n at DryIoc.Container.ResolveAndCacheDefaultDelegate(Type serviceType, Boolean ifUnresolvedReturnDefault, IScope scope)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
第一次尝试应该改为:
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
// Resolve service first then inject properties into it.
var ws = c.Resolve<IWidgetService>();
c.InjectPropertiesAndFields(ws);
}
仅从代码进行的第二次尝试应该可以,但也可能是其他原因。要找出答案,您可以将规则更改为:
PropertiesAndFields.All(withNonPublic: false, withPrimitives: false, withFields: false, ifUnresolved: IfUnresolved.Throw)
不过,更好的选择是为精确服务指定精确 属性:
c.Register<IWidgetService, WidgetService>(Reuse.Singleton,
made: PropertiesAndFields.Of.Name("WidgetRepository"));
或强类型:
c.Register<IWidgetService, WidgetService>(
Made.Of(() => new WidgetService { WidgetRepository = Arg.Of<IWidgetRepository>() }),
Reuse.Singleton);
更新:
DryIoc 设计时采用了最不意外的默认设置:类型为 DI 的单个构造函数且没有 属性 注入。但是您可以选择默认值以简化迁移:
IContainer c = new Container(Rules.Default.With(
FactoryMethod.ConstructorWithResolvableArguments,
propertiesAndFields: PropertiesAndFilds.Auto);
对于你的情况来说可能就足够了。
如果没有,您可以添加规则:
.WithFactorySelector(Rules.SelectLastRegisteredFactory())
.WithTrackingDisposableTransients()
.WithAutoConcreteTypeResolution()
更新 2:
这个测试对我有用。
[Test]
public void Controller_with_property_injection()
{
var config = new HttpConfiguration();
var c = new Container()
.With(rules => rules.With(propertiesAndFields: PropertiesAndFields.Auto))
.WithWebApi(config, throwIfUnresolved: type => type.IsController());
c.Register<A>(Reuse.Singleton);
using (var scope = config.DependencyResolver.BeginScope())
{
var propController = (PropController)scope.GetService(typeof(PropController));
Assert.IsNotNull(propController.A);
}
}
public class PropController : ApiController
{
public A A { get; set; }
}
public class A {}
但将PropertiesAndFields.Auto
改为
PropertiesAndFields.All(false, false, false, IfUnresolved.Throw)
产生了更新 3 的错误。
更新 3:
感谢您上传 sample repo,它有助于找到问题。
DryIoc PropertiesAndFields.Auto
规则将注入所有声明的和 base class 属性,这会导致 base ApiController
中定义的某些属性出错class。好处是 Auto
只是一个预定义规则,您可以定义自己的规则以排除基础 class 属性:
private static IEnumerable<PropertyOrFieldServiceInfo> DeclaredPublicProperties(Request request)
{
return (request.ImplementationType ?? request.ServiceType).GetTypeInfo()
.DeclaredProperties.Where(p => p.IsInjectable())
.Select(PropertyOrFieldServiceInfo.Of);
}
然后像这样创建容器:
var c = new Container()
.With(rules => rules.With(propertiesAndFields: DeclaredPublicProperties))
.WithWebApi(config, throwIfUnresolved: type => type.IsController());
我已经提交了 PR 和修复。
BTW 在未来/下一个 DryIoc 版本中,我将提供 API 来简化基础或仅声明 属性 选择。
好的,忽略我最后的评论,可能不相关。查看异常堆栈跟踪,WebAPI 似乎回退到对控制器使用 Activator.CreateInstance,那是因为 DryIoc 无法解析它。但是回退掩盖了实际的 DryIoc 错误。要找出答案,请尝试:
container.WithWebApi(throwIfUnresolved: type => type.IsController());