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!
Can we bind Bind(typeof(IRepo)).To(typeof(Repo)) ? here Repo has more number of parameters than IRepo.