Monday, February 14, 2011

Removing the NInject dependency from the Domain model and Entity Framework classes.

Hi, folks this post is continuation of my previous post Entity Framework CTP5 injecting with NInject. Let's have a brief revision. We have created a model "Member" class that has dependency on a MemberRepository and an AuthenticationService. We also have created a DbContext class that is capable of injecting the dependencies to created Entities.

One thing that I really don't like about the implementation is that, now the Model as well as the Datacontext is dependent on the NInject framework. Although I'm beginning to love NInject as a dependency framework, but I think the application as whole should be unaware of an IoC framework (As Nate says it is matter of opinion). Now, lets move ahead and try to remove dependency from the NInject framework.

I will first focus on the Member class, as I cannot specially bear to have a NInject dependency in my Domain model. One cool feature of NInject is that it provides the developers with ways to change the manner in which the dependencies are injected. That means although by default it uses "Inject" attribute we can change that behavior. Since, the name of method "InjectDependency" is quite self explanatory, I think it becomes quite unnecessary to decorate that method with extra attribute whose sole purpose is to point out "hey this method should be used to inject the external dependencies".

Here's how we do it. Below is a NInject heuristic that can decides whether to consider a method as an entry point for dependency injection or not. The decision is made based on a lamda expression.
public class NInjectMemberSelector : NinjectComponent, IInjectionHeuristic
{

  public bool ShouldInject(System.Reflection.MemberInfo member)
  {
    return member.MemberType == MemberTypes.Method && _predicate(member);
  }

  private readonly Func<MemberInfo, bool> _predicate;

  public NInjectMemberSelector(Func<MemberInfo, bool> predicate)
  {
    _predicate = predicate;
  }

}
Now let's create a NInject module that uses this heuristics.
public class InjectAllMethodsNamedInjectDependencyModule : NinjectModule
{
  public override void Load()
  {
    var selector = Kernel.Components.Get<ISelector>();
    //specify that a method with name "InjectDependency",should be considered as an entry point for Injection.
    var heuristic = new NInjectMemberSelector(member => member.Name.Equals("InjectDependency"));
    selector.InjectionHeuristics.Add(heuristic);
  }
}
This module now needs to be registered to the NInject Kernel.
  IKernel kernel = new StandardKernel();
  kernel.Load(new InjectAllMethodsNamedInjectDependencyModule());
Now, a simple way to avoid NInject dependency from the DbContext. Let's create an Interface named IInject and a class NInjectAdapter that implements the interface
public interface IInject
{
  void Inject(object objectToInject);
}

public class NinjectAdapter : IInject
{
  private IKernel _kernel;

  public NinjectAdapter(IKernel kernel)
  {
    _kernel = kernel;
  }

  public void Inject(object objectToInject)
  {
    _kernel.Inject(objectToInject);
  }
}
Now, let's use our custom IInject interface instead of instead of the IKernel
public class NInjectDataContext : DbContext
{
  //modified IKernel to IInject
  public NInjectDataContext(DbConnection dbconnection,  IInject kernel): base(dbconnection)
  {
    this.Kernel = kernel;
    (this as IObjectContextAdapter).ObjectContext.ObjectStateManager.ObjectStateManagerChanged += ObjectStateManagerChanged;
  }

  //other thing remains as it is.....
  //...

  //modified IKernel to IInject
  public IInject Kernel
  {
    get;
    private set;
  }
}
This is it, we have removed the dependency on NInject from our domain model as well as the DbContext class. Hope this would help someone.

No comments:

Post a Comment