2016-11-29 5 views
0

Возможно, мой подход неверен, но я хотел бы изложить фактические требования перед моей попыткой разрешения. Мой подход основан на деталях, предоставленных hereNinject, чтобы вернуть имплантацию на основе перечислителя

Задача: в ориентированной на мастера структуре получить объект BaseWizardStepNavigator на основе текущего шага. Например, если я на этапе WizardStep.Step1, верните экземпляр Step1Navigator. Экземпляр Step1Navigator должен иметь любые впрыскиваемые сборки, поставляемые в его конструкторе, так что если у меня есть;

public class Step1Navigator : BaseWizardStepNavigator 
{ 
    private readonly ISomeReader _reader; 
    public Step1Navigator(ISomeReader reader) 
     : base(WizardSteps.Step1) 
    { 
     _reader = reader; 
    } 
} 

... что аргумент reader заполняется соответствующей реализации.

Моя идея состоит в том, что у меня будет объект-менеджер, который ninject может создать, передав во всех реализациях базового класса (с соответствующими инъекциями IoC), что;

public class NavigatorManager 
{ 
    private readonly List<BaseWizardStepNavigator> _navigators; 
    public class NavigatorManager(IEnumerable<BaseWizardStepNavigator> navigators) 
    { 
     _navigators = new List<BaseWizardStepNavigator>(navigators); 
    } 
    public BaseWizardStepNavigator Get(WizardStep step) 
    { 
     return _navigators.FirstOrDefault(n => n.Step == step); 
    } 
} 

Там в конечном итоге будет 10-х шагов мастера с соответствующими навигаторов, чтобы определить, какой следующий шаг, но они должны ударить DB иногда, чтобы сделать это.

Моя текущая попытка и выполнение привязки в NinjectModule, где я использую Ninject и Ninject.Conventions;

Модуль (способ загрузки);

Kernel.Bind(s => s.FromAssemblyContaining(typeof(BaseWizardStepNavigator)) 
        .SelectAllClasses() 
        .WhichAreNotGeneric() 
        .InheritedFrom<BaseWizardStepNavigator>() 
        .BindWith<NavigatorBinding>()); 
var test = Kernel.GetAll<BaseWizardStepNavigator>(); 

Затем другие классы для привязок и поставщиков;

public class NavigatorBinding : IBindingGenerator 
{ 
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot) 
    { 
     if (type.IsInterface || type.IsAbstract) 
     { 
      yield break; 
     } 

     yield return bindingRoot.Bind(typeof(BaseWizardStepNavigator)).ToProvider<NavigatorProvider>(); 
    } 
} 

public class NavigatorProvider : IProvider<BaseWizardStepNavigator> 
{ 
    public object Create(IContext context) 
    { 
     return null; 
    } 

    public Type Type { get { throw new NotImplementedException(); } } 
} 

Теперь, в то время как вызов kernel.GetAll<BaseWizardStepNavigator>() действительно вызвать Provider методы реализации, я немного потерял о том, как на самом деле заставить его выплюнуть обратно объекты. Документация неясна, и я не совсем уверен, что я даже на правильном пути. Помогите?

+0

Даже если ваш менеджер получает список навигаторов в своем конструкторе, как он будет определять, какой из них следует возвращать на основе WizardStep? Мне кажется, что вам нужна карта какого-то типа между шагами и обработчиками. – JuanR

+0

@ Juan есть, хотя я не включил его в пример выше. Конструктор 'BaseWizardStepNavigator' принимает аргумент' WizardStep', который должен указать каждый ребенок. В методе 'Get()' я смогу сделать 'if (manager.Step == step) return manager;'. Проблема заключается в реализации IProvider. Я не знаю, как заставить его выбирать и возвращать соответствующие объекты. – DiskJunky

+0

Это было бы намного проще, если бы вы использовали интерфейсы вместо шагов для определения класса. Поскольку вы используете контейнер DI, просто создайте интерфейс для каждого шага и сопоставьте класс в контейнере. – JuanR

ответ

0

Мне удалось получить реализацию, работающую довольно просто в конце. Не было необходимости в IBindingGenerator или IProvider реализациях.

Код для Step1Navigator и NavigatorManager не меняется.

NinjectModule код привязки к;

// set the navigator bindings 
Kernel.Bind(s => s.FromAssemblyContaining(typeof(BaseWizardStepNavigator)) 
        .SelectAllClasses() 
        .WhichAreNotGeneric() 
        .InheritedFrom<BaseWizardStepNavigator>() 
        .BindAllBaseClasses() 
        .Configure(c => c.InRequestScope()) 
       ); 

// pass in all children of BaseWizardStepNavigator to the manager instance 
Bind<NavigatorManager>().ToSelf() 
         .InRequestScope() 
         .WithConstructorArgument(typeof(IEnumerable<BaseWizardStepNavigator>), 
                n => n.Kernel.GetAll<BaseWizardStepNavigator>()); 

.InRequestScope() относится к веб-приложениям. Измените, если это необходимо, если вы используете это в своем собственном коде до .InSingletonScope() и т. Д.