Ninject -Targeted Bindings


I know this topic has been done to death on StackOverflow, Ninject.Extensions created to solve it, and a million other things.  But what if I wanted to use vanilla Ninect in a small solution and didn’t want to use Ninject.Extensions, but still wanted to Bind a bunch of classes at once?  I couldn’t find an easy answer, so it’s possible someone else wouldn’t find an easy answer.  So here’s an answer using simple reflection.  The lazy person in me is going to limit sanitizing code, so pardon the specificity of the variable names, but chances are you’ll need it for the same things.

How did this adventure begin?  Simple: I’m helping a buddy learn how to do Windows.Forms development (GASP! It does still exist!), and he’s using Ninject.  And he is setting up to do something like 100+ repositories, 60+ List forms, 60+ CRUD forms, and some reports and what not.  Now, imagine you had to manually bind all of those in a module.  My fingers hurt just thinking about it, so I decided to look for a better way.

Step 1: The Problem

The setup.  An IRepository<T> that exists to allow common CRUD for a model, and a concrete implementation, e.g. StandardSettingRepository: IRepository<StandardSettings>.  This would typically be done like so:

Bind(typeof(IRepository<StandardSettings>)).To(typeof(StandardSettingRepository));

Clean, easy, readable… until you do it 100 times.

Step 2: The Elegant Solution

Enter Ninject.Extensions — an example can be seen here: http://stackoverflow.com/questions/15259175/how-do-i-bind-generic-types-with-inheritance-using-ninject-conventions-extension

But I thought.. man, that’s an impressive wheel, but I just need a tack and a cardboard circle, not the landing gear of a space shuttle.  Can I roll my own?

Step 3: Denial.

Sure, Ninject.Extensions is probably the way to go, but I like my answer, and it seems to work.  Maybe you will to.

var repositoryType = typeof(IRepository<>);
var repos = repositoryType.Assembly.GetTypes().Where(x => !x.IsInterface && x.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == repositoryType));
foreach(var repo in repos)
{
    var iface = repo.GetInterfaces().FirstOrDefault(y => y.IsGenericType && y.GetGenericTypeDefinition() == repositoryType);
    if (iface == null) continue;
    var genArgs = iface.GetGenericArguments();
    var genInterface = repositoryType.MakeGenericType(genArgs);
    Bind(genInterface).To(repo);
 }

The basic idea here is to get everything that is not an interface, implements a generic version of our interface, and then bind it to the generic version of the interface.  It’s clean, and pulls only from the assembly the IRepository<> interface resides, which allows you to hide it in a small library and be quickly searchable.  I also needed this for a generic way to pull CRUD forms out from a library, so I reused the pattern:

 //Editors
 var editorType = typeof(IDataGridModelEditView<>);
 var editors = editorType.Assembly.GetTypes().Where(x => !x.IsInterface && x.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == editorType));
 foreach (var repo in editors)
 {
    var iface = repo.GetInterfaces().FirstOrDefault(y => y.IsGenericType && y.GetGenericTypeDefinition() == editorType);
    if (iface == null) continue;
    var genArgs = iface.GetGenericArguments();
    var genInterface = editorType.MakeGenericType(genArgs);
    Bind(genInterface).To(repo);
 }

Nothing pretty, but it is functional, fast, and doesn’t require any additional libraries.  Happy Coding!

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s