我正在構建一個框架,我不想將它耦合到特定的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