Runtime binding: a simple task runner with ninject?

I am writing a simple application to run a task.

I have a bunch of classes that implement the ITask interface:

public interface ITask { void Run(); } 

I am writing a simple console application that creates ITasks instances and then calls Run () for each of them. Task implementations use constructor installation, so I would like to use ninject.

I would like to be able to specify during the execution of the task to run and therefore which ITask implementation to activate.

I thought I could nest specific types in my app.config, and then at runtime I could get ninject to create an ITask array from it. Otherwise, I could specify the tasks that I want to run on the command line.

For me, this sounds like a pretty straight forward case for ninject, but I was not able to find how to get ninject to bind from a configuration or string.

Can someone point me in the right direction?

+6
ninject
source share
2 answers

There are extensions for ninject that handle things like xml configuration.

I would be careful about mixing the programming bits from config a la Spring XML config, although there is no need to go into the XML configuration to allow people to customize things in the .config file. I suggest reading the loader of the XML configuration section, which is serialized in a class that expresses this at a higher level.

You use the metadata mechanism in your bind registers, and then specify how to filter the task set based on this.

for example, reprogramming @ Ian Davis answer (read it and release now!):

 string metaDataKey = "key"; kernel.Bind<IWeapon>().To<Shuriken>().WithMetadata(metaDataKey, true); kernel.Bind<IWeapon>().To<Sword>().WithMetadata(metaDataKey, false); kernel.Bind<IWeapon>().To<Knife>(); bool? theOneIWant = null; // or true or false - ie, the distillation of what your config says Func<IMetadata> myConfigSaysIWantOneLikeThatPredicate= metadata => metadata.Has(metaDataKey) == theOneIWant != null && metadata.Get<bool>(metaDataKey) == theOneIWant.Value var weapons = kernel.Get<IEnumerable<IWeapon>>( myConfigSaysIWantOneLikeThatPredicate ); // the above will generate a single item given the bindings above, but you get the picture - this generates an arbitrary length list foreach(var weapon in weapons) weapon.Fire(); 

If all you are looking for is their name, there is an abbreviated replacement for WithMetadata called Named() and an overload for .Get<T>() with a name string parameter, which allows you to achieve @dave a simple teeb, without your calls were tightly bound to type names.

EDIT: Example, see comments:

 using Ninject; using System; using System.Collections.Generic; using System.Linq; using Xunit; namespace ninjectmess { public class Class1 { 

Some classes of spam messages

  public interface ITask { } public class Aasdsdaadsdsa : ITask { } public class Bdsadsadasdsadsadsa : ITask { } public class Cddsadasdsadasdas : ITask { } 

actual test

  [Fact] public void TestMethod() { var k = new StandardKernel(); k.Bind<ITask>().To<Aasdsdaadsdsa>().Named( "A" ); k.Bind<ITask>().To<Bdsadsadasdsadsadsa>().Named( "B" ); k.Bind<ITask>().To<Cddsadasdsadasdas>().Named( "C" ); var wanted = new string[] { "A", "C" }; var tasks = k .GetAll<ITask>( metadata => wanted.Contains( metadata.Name )) .ToList(); Assert.Equal( 2, tasks.Count ); tasks.ForEach( Console.WriteLine ); } } } 
+6
source share

I like the Ruben answer, but it can be as simple as using the type names of the required tasks on the command line:

 public static void Main( string[] args ) { var kernel = new StandardKernel(); var tasks = new List<ITask>(); foreach(var taskName in args) { tasks.Add( kernel.Get( Type.GetType( taskName ) ) ); } doSomething(tasks); } 
+3
source share

All Articles