Using Reflection with Dependency Injection

Posted by:

So recently we were working on a large enterprise project that involved Entity Framework 5, Repositories and Dependency Injection. We were working with a previously designed database, so every time we wanted to bring an entity into the project, we needed to create the entity, create it’s code-first map and add the map and the collection to the context. To top that off, we then had to go into our Ninject bindings and add a binding for the repositories.

I noticed that when my developers were adding entities, they continually forgot to add the repository bindings to Ninject (and I too forgot on occasion). I decided there had to be a better way and I decided to dig deeper into reflection. Finally, after a few hours of tinkering, this is what I came up with:

All of my domain objects implement a simple interface called IEntity. This interface is used to designate any c# object that represents an EF5 entity.

My Ninject bindings bind a GenericRepository<> to an IRepository<>. I recognize that some people will use a different repository for each entity, but in our Enterprise, the Generic repository has been well-written over time and is able to handle all of the repository needs with very rare occurrences in which it must be extended.

Finally, using some reflection and Linq, I was able to come up with this method in my NinjectModule to handle my bindings:

protected void ReflectRepositoryBindings()
{
    Logger.Info("Reflecting Repository Assemblies");
    var iRepo = typeof(IRepository<>);
    var genRepo = typeof(GenericRepository<>);

    var types = from t in Assembly.GetAssembly(typeof(IEntity)).GetTypes()
                where t.IsClass && !t.IsAbstract
                    && t.GetInterfaces().Contains(typeof(IEntity))
                select t;

    foreach (var type in types)
    {
        var iTypeRepo = iRepo.MakeGenericType(type);
        var genTypeRepo = genRepo.MakeGenericType(type);
        //Bind the interface type to the generic repository type
        Bind(iTypeRepo).To(genTypeRepo);
        Logger.Debug("Bound GenericRepository<" + type.Name 
                         + "> to IRepository<" + type.Name + ">");
    }
}

OK, so to explain whats going on here, I’m getting the type of an empty IRepository<> and GenericRepository<>. Then I’m using Assembly reflection to find the assembly which contains the IEntity interface and then fetch all of the types from that assembly that are non-abstract classes that implement that interface. Finally, I iterate over all the types that match that criteria and, once again using reflection, am able to attach the Generic to the IRepository and GenericRepository types to create a complete type. Once I have each of them, I am able to use the Ninject Bind() and To() methods to complete the bindings.

I then just call this method in my Ninject Module’s Load() method. If any of these default bindings need to use an extended repository, then after the reflection bindings, I just call Ninject’s Rebind() method to do so. Volia! Now, I can just create entities and mappings and the DI binding is handled for me in runtime. 🙂 Cheers!

0
  Related Posts

Add a Comment