It's entirely possible my approach is incorrect but I'd like to outline the actual requirements first before my attempt at a resolution. My approach is based on the details provided here
Task: in a wizard oriented stucture, get a BaseWizardStepNavigator
object based on the current step. E.g., if I'm on step WizardStep.Step1
, return instance of Step1Navigator
. The instance of Step1Navigator
should have any injected assemblies supplied in its constructor such that if I have;
public class Step1Navigator : BaseWizardStepNavigator
{
private readonly ISomeReader _reader;
public Step1Navigator(ISomeReader reader)
: base(WizardSteps.Step1)
{
_reader = reader;
}
}
...that argument reader
is populated with the appropriate implementation.
My idea is that I'd have a manager object that ninject can instantiate by passing in all implementations of the base class (with appropriate IoC injections) such that;
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);
}
}
There will eventually be 10's of wizard steps with appropriate navigators to determine what the next step is but they'll need to hit the DB occasionally to do that.
My current attempt and performing the binding in a NinjectModule
where I'm using Ninject and Ninject.Conventions is;
Module (load method);
Kernel.Bind(s => s.FromAssemblyContaining(typeof(BaseWizardStepNavigator))
.SelectAllClasses()
.WhichAreNotGeneric()
.InheritedFrom<BaseWizardStepNavigator>()
.BindWith<NavigatorBinding>());
var test = Kernel.GetAll<BaseWizardStepNavigator>();
Then other classes for the bindings and provider;
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(); } }
}
Now, while the call to kernel.GetAll<BaseWizardStepNavigator>()
does call the Provider
implementation methods, I'm a bit lost as to how to actually get it to spit back the objects. The documentation is obscure and I'm not entirely certain I'm even on the correct path. Help?
I managed to get an implementation working fairly simply in the end. There was no need for
IBindingGenerator
orIProvider
implementations.Code for
Step1Navigator
andNavigatorManager
remains the same.NinjectModule
binding code changes to;The
.InRequestScope()
is specific to web applications. Change as appropriate if you're using this in your own code to.InSingletonScope()
, etc.