Я создаю среду, которую не хочу связывать с конкретным контейнером IOC, поэтому создал слой поверх Ninject / Structuremap и т. Д.
У меня есть класс привязки, который принимает 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контейнер.Это не зависит от какой-либо конкретной структуры МОК.Когда я создаю экземпляр 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 'fail: 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.GetTInBostoc.cs (149,0): в Ioc.Test.IocTestBase.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module ()