2016-11-29 1 views
0

Il est tout à fait possible que mon approche soit incorrecte, mais je voudrais décrire les exigences réelles avant de tenter une résolution. Mon approche est basée sur les détails fournis hereNinject retourner l'implentation basée sur l'énumérateur

Tâche: dans une structure orientée par assistant, obtenez un objet BaseWizardStepNavigator en fonction de l'étape en cours. Par exemple, si je suis à l'étape WizardStep.Step1, retour instance de Step1Navigator. L'instance de Step1Navigator doit avoir tous les assemblages injectés fournis dans son constructeur de telle sorte que si j'ai;

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

... cet argument reader est rempli avec la mise en œuvre appropriée. Mon idée est que j'aurais un objet manager que ninject peut instancier en passant dans toutes les implémentations de la classe de base (avec des injections IoC appropriées) de telle sorte que;

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); 
    } 
} 

Il y aura éventuellement 10 des étapes de l'assistant avec les navigateurs appropriés pour déterminer la prochaine étape est, mais ils auront besoin de frapper la DB de temps en temps pour le faire.

Ma tentative actuelle et l'exécution de la liaison dans un NinjectModule où j'utilise Ninject et Ninject.Conventions est;

Module (méthode de chargement);

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

Puis d'autres classes pour les liaisons et le fournisseur;

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(); } } 
} 

Maintenant, alors que l'appel à kernel.GetAll<BaseWizardStepNavigator>() n'appelle les Provider méthodes de mise en œuvre, je suis un peu perdu quant à la façon d'obtenir effectivement à recracher les objets. La documentation est obscure et je ne suis pas tout à fait certain d'être sur le bon chemin. Aidez-moi?

+0

Même si votre gestionnaire obtient une liste de navigateurs dans son constructeur, comment va-t-il déterminer lequel doit retourner en fonction de WizardStep? Il me semble que vous avez besoin d'une carte quelconque entre l'étape et les gestionnaires. – JuanR

+0

@Juan il y a bien que je ne l'ai pas inclus dans l'exemple ci-dessus. Le constructeur 'BaseWizardStepNavigator' prend un argument de' WizardStep' que chaque enfant doit spécifier. Dans la méthode 'Get()', je serai capable de faire 'if (manager.Step == step) return manager;'. Le problème est l'implémentation 'IProvider'. Je ne sais pas comment l'obtenir pour sélectionner et retourner les objets appropriés – DiskJunky

+0

Cela serait beaucoup plus simple si vous utilisiez des interfaces au lieu d'étapes pour identifier la classe. Puisque vous utilisez un conteneur DI, créez simplement une interface pour chaque étape et associez la classe dans le conteneur. – JuanR

Répondre

0

J'ai réussi à faire fonctionner une implémentation assez simplement à la fin. Il n'y avait pas besoin d'implémentations IBindingGenerator ou IProvider.

Le code pour Step1Navigator et NavigatorManager reste le même.

NinjectModule le code de liaison passe à;

// 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>()); 

Le .InRequestScope() est spécifique aux applications Web. Modifiez le cas échéant si vous l'utilisez dans votre propre code à .InSingletonScope(), etc.