Ninject binding based on string
c#, ninject
Solution
If the classes that you present in your example code are accurate (i.e. there is not a bunch more methods and properties). Then the simplest possible solution might work, and you can get rid of a number of classes / dependencies on classes.
A simple solution, that does not rely on a framework/container would be:
public static class FormsProcessing
{
private static ConcurrentDictionary<string, Func<FormProcessor>> _registeredProcessors = new ConcurrentDictionary<string, Func<FormProcessor>>();
public delegate bool FormProcessor(XmlDocument form);
public static void RegisterProcessor(string formKey, Func<FormProcessor> formsProcessorFactory)
{
_registeredProcessors.AddOrUpdate(formKey, formsProcessorFactory, (k, current) => formsProcessorFactory);
}
public static FormProcessor GetProcessorFor(string formKey)
{
Func<FormProcessor> processorFactory;
if (_registeredProcessors.TryGetValue(formKey, out processorFactory);
return processorFactory();
return null;
}
public static bool Process(string formKey, XmlDocument form)
{
var processor = GetProcessorFor(formKey);
if (null == processor)
throw new Exception(string.Format("No processor for '{0}' forms available", formKey));
return processor(form);
}
}
Usage:
namespace Web.Services
{
public class MyServiceClass
{
public bool AddForm(XmlDocument form, string formName)
{
return FormsProcessing.Process(formName, form);
}
}
}
It is simple and explicit, and does not need or expose any dependency on some structure of `IPFormDataContext` and `IPFormDataStrategy` classes. The only explicit dependency you have is on a delegate that has the `FormProcessor` signature.
Similar to a container, you will need to perform the registrations somewhere:
FormsProcessing.RegisterProcessor("FormA", () => new FormAStrategy().DoWork);
FormsProcessing.RegisterProcessor("FormB", () => new FormBStrategy().DoWork);
Alternatively it would be easy to add some form of (convention based) auto registration by scanning assemblies for the convention (e.g. an interface signature).
Problem
I have a web service that's going to do things with some data being passed in (specifically InfoPath xml from a SharePoint doc library). I'm currently using Ninject to handle what form data "strategy" to load. Here's some code (question follows): Web Service (Entry Point) ``` namespace Web.Services { public bool AddForm(XmlDocument form, string formName) { IKernel kernel = new StandardKernel(new FormsModule()); var ctx = kernel.Get<IPFormDataContext>(formName); return ctx.DoWork(form); } } ``` Ninject Related Things ``` namespace Core.Modules { public class FormsModule : NinjectModule { public override void Load() { Bind<IPFormDataContext>().ToSelf().Named("FormA"); Bind<IPFormDataContext>().ToSelf().Named("FormB"); // Snip Bind<IPFormDataStrategy>().To<FormAStratgey>() .WhenParentNamed("FormA"); Bind<IPFormDataStrategy>().To<FormBStrategy>() .WhenParentNamed("FormB"); // Snip } } } ``` Pattern Related Things ``` namespace Core.Forms { public class IPFormDataContext { private IPFormDataStrategy _ipFormDataStrategy; public IPFormDataContext(IPFormDataStrategy strategy) { _ipFormDataStrategy = strategy; } public bool DoWork(XmlDocument form) { return _ipFormDataStrategy.DoWork(form); } } public abstract class IPFormDataStrategy { public abstract bool DoWork(XmlDocument form); } } namespace Core.Forms.FormStrategies { class FormAStrategy : IPFormDataStrategy { public override bool DoWork(XmlDocument form) { // Deserialize form using (xsd.exe generated) FormAData // and perform some operation on the resulting data. return resultOfWork; } } } ``` FormBStrategy is much the same, as is the 7 other strategies I didn't list. I'm trying to find a way to pass in a form xml to the webservice and call the correct form deserialization based on the form type that's coming in. The code above "works"; but it feels like I'm doing some sort of service location in Ninject, which from what I'm reading is a bad thing. But I can't think of a proper way to accomplish this. I'm not dead set on using Ninject, or any IOC/DI framework for that matter. Is what I'm doing ... wrong? Could I get pointed in the right direction?