我正在构建一个框架,我不想将它耦合到特定的IOC容器,因此在Ninject/structuremap之上创建了一个图层等。当有多个方法绑定类型时,Ninject绑定到错误的匿名方法
我有一个绑定类,它接受一个Func来允许绑定到一个方法。
例如
public class Binding
{
public Type Source { get; set; }
public Func<object> Method {get; set; }
public Scope { get; set; }
}
如果我有一个结合样......
var binding = new Binding() {
Source = typeof(IRepository),
Method =() => new Repository(new LinqToSqlRepository(connectionString)),
Scope = Scope.HttpRequest
};
框架包裹Ninject会为我的通用Ninject绑定这样
Module :NinjectModule
{
IList<Binding> _Bindings;
public Module(IList<Binding> bindings)
{
_Bindings = bindings;
}
public override void Load() {
foreach (var binding in _Bindings) {
switch(binding.Scope) {
case IocScope.HttpRequest:
Bind(binding.Source).ToMethod(c => binding.Method()).InRequestScope();
break;
// ... omitted for brevity
}
}
}
}
这种结合当只有一个绑定绑定到方法时可以正常工作。当同一个模块中有多个绑定绑定到方法时,返回不正确的类型。从调试开始,它看起来好像总是使用最后一个绑定。
因此用一个例子来说明问题;
var binding1 = new Binding() {
Source = typeof(IRepository),
Method =() => new Repository(new LinqToSqlRepository(connectionString)),
Scope = Scope.HttpRequest
};
var binding2 = new Binding() {
Source = typeof(ICalendar),
Method =() => new MvcCalendar(.....)
Scope = Scope.HttpRequest
};
在运行时Ninject被请求新建立一个MVC控制器这需要在IRepository和显示iCalendar,收到一个类型转换错误,指出一个MvcCalendar不能被转换为IRepository。我发现由于某种原因,最后的绑定总是返回第一个请求的类型。
这是一个非常简化的版本,它试图强调实际问题,当有多个方法绑定时,将错误的方法绑定到请求的类型。我希望这仍然可以解释这个问题。
这似乎与某种关闭范围界定问题有关。我还想知道Ninject是否正在被Func弄糊涂而不是Func的使用。
单元测试例
这是一个测试模块我加载到我的自定义IOC容器。这不取决于任何特定的IOC框架。当我实例化一个NinjectIocContainer处理DI,这在Ninject内部发生结合如实施例进一步向上(见NinjectModule)
public class MultipleMethodBoundTypesModule : IocModule
{
public override void Load()
{
Bind<IPerson>().To(() => new Person()).In(IocScope.Transient);
Bind<IRobot>().To(() => new Robot(new Person())).In(IocScope.Transient);
}
}
下面是一个简单的测试,尝试检索每个类型。
[Test]
public void Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module()
{
// arrange
var container = Get_Container_With_Module(new MultipleMethodBoundTypesModule());
// act
var person = container.Get<IPerson>();
var robot = container.Get<IRobot>();
// assert
Assert.IsNotNull(person);
Assert.IsNotNull(robot);
}
作为早期的教解释的那样,这将引发其中最后闭合(用于机器人)被绑定到一个人的类型转换。
TestCase的 'Ioc.Test.NinjectContainerTest.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module' 失败:System.InvalidCastException:无法投型 'Ioc.Test.Robot' 的对象键入 'Ioc.Test.IPerson'。 在System.Linq.Enumerable.d__b1
1.MoveNext() at System.Linq.Enumerable.Single[TSource](IEnumerable
1个源) 在Ninject.ResolutionExtensions.Get [T](IResolutionRoot根,IParameter []参数) NinjectIocContainer.cs(40,0):在Ioc.Ninject.NinjectIocContainer。GetTInstance IocTestBase.cs(149,0):在Ioc.Test.IocTestBase.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module()
我没有我面前的代码,在我头上打字并在.ToMethod(binding.Method())中输入错字。由于这是一个Ninject绑定,它实际上应该包含一个上下文; (c => binding.ToMethod())。我已经更新了原来的问题来反映这一点。再一次,在这个范围上是正确的,因为这是在NinjectModule中。我在链接'封闭混乱'文章中注意到类似问题,其中重复了forloop的最后一个值。然而,我不完全确定如何将其应用于我的案例。 – 2010-10-19 06:42:00
对于基元来说,它的值会被复制,但是如何返回我认为会由ref返回的对象时,它是如何应用的。 – 2010-10-19 07:04:12
@Joshua Hayes:不幸的是,没有你的代码库和VS在我面前,我不觉得我可以猜测任何更有用的方向。仍然不明白你为什么要存储一个范围,然后使用.InRequestScope()。最后一点,我没有做 - 我想知道为什么你觉得你需要抽象容器,而不去CSL路线。我个人通常使用ctor注入,并使代码容器保持中立 - 让这一层变得混乱 - 但我相信您的情况与我目前正在使用的代码库类型不同...... – 2010-10-19 10:00:27