Ninject not injecting and throwing null reference exceptions
I'm new to Ninject so I'm sure that it's something I'm doing wrong, I'm just not sure what. I'm using Ninject and Ninject.MVC3 in my MVC3 web application. Here's an example of what I'm trying to do.
I'm using the Repository pattern:
public interface IRepository<T>
{
T Get(object id);
IList<T> GetAll();
void Add(T value);
void Update(T value);
void Delete(T value);
}
For a concrete type:
public Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Customer()
{
}
}
Now I have 2 separate repositories, a cached version that needs injection to the database repository:
public CachedCustomerRepository : IRepository<Customer>
{
private IRepository<Customer> _repository;
public Customer Get(object id)
{
Customer cust = new Customer();
IList<Customer> custs = GetAll();
if (custs != null && custs.Count > 0)
cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString()));
return cust;
}
public IList<Customer> GetAll()
{
IList<Customer> custs = HttpRuntime.Cache["Customers"] as IList<Customer>;
if (custs == null)
{
custs = _repository.GetAll();
if (custs != null && custs.Count() > 0)
{
double timeout = 600000d;
HttpRuntime.Cache.Insert("Customers", custs, null, DateTime.UtcNow.AddMilliseconds(timeout), System.Web.Caching.Cache.NoSlidingExpiration);
}
else
{
throw new NullReferenceException();
}
}
return custs;
}
public void Add(Customer value)
{
throw new NotImplementedException();
}
public void Update(Customer value)
{
throw new NotImplementedException();
}
public void Delete(Customer value)
{
throw new NotImplementedException();
}
public CachedCustomerRepository()
{
}
[Inject]
public CachedCustomerRepository(IRepository<Customer> repository)
{
_repository = repository;
}
}
public class CustomerRepository : IRepository<Customer>
{
public Customer Get(object id)
{
Customer cust = new Customer();
IList<Customer> custs = GetAll();
if (custs != null && custs.Count > 0)
cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString()));
return cust;
}
public IList<Customer> GetAll()
{
//Customer retrieval code
}
public void Add(Customer value)
{
throw new NotImplementedException();
}
public vo开发者_开发问答id Update(Customer value)
{
throw new NotImplementedException();
}
public void Delete(Customer value)
{
throw new NotImplementedException();
}
public CachedCustomerRepository()
{
}
}
I set up a NinjectModule like this:
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IRepository<Customer>>().To<CustomerRepository>();
}
}
and I modified the NinjectMVC3.cs in the AppStart folder to get the module when creating the kernel:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel(new ServiceModule());
RegisterServices(kernel);
return kernel;
}
In my controller I am using this:
public ViewResult Index()
{
IRepository<Customer> custRepo = new CachedCustomerRepository();
return View(custRepo.GetAll());
}
It blows up on the line _repository.GetAll()
in my CachedCustomerRepository
.
I've set a breakpoint to make sure that the CreateKernel()
is executing and getting the bindings, which it is. I'm just not sure why the injection isn't happening. One other side note, I don't know if it's important or not, the IRepository, the Repositories and the concrete type are in a separate class library and is referenced in the mvc3 web app. Both the web app and the class library have a reference to Ninject and the web app also has a reference to Ninject.MVC3. The binding and kernel creation is all taking place in the Web App.
First, you're calling the wrong constructor in your controller. This parameterless constructor doesn't call anything else and that's why you're getting the null exception. Second, you want to refactor your controller so that there are no direct dependencies.
You'd want to do something like the following:
public class SomeController
{
private readonly IRepository<Customer> repo;
public SomeController(IRepository<Customer> repo)
{
this.repo = repo;
}
public ViewResult Index()
{
return View(this.repo.GetAll());
}
}
This way, Ninject resolves the dependency for you! Ninject's kernel will be asked to create a controller with IRepository<Customer>
by MVC. Since Ninject has this "binding", it'll try to instantiate the CustomerRepository
for you.
Also, why are you creating a "CachedRepository"? I really, really think you're prematurely optimizing this. Honestly, you only need the one CustomerRepository
and you'd wire that up within the Ninject module.
Have you made the class in Global.asax
inherit NinjectHttpApplication
?
Make sure you're calling DependencyResolver.SetResolver(CreateKernel());
in order to tell MVC which resolver you're going to use. You might be calling it but I didn't see it in your post - otherwise your code looks fine.
To get the full benefit of using an IOC you should refactor the CachedCustomerRepository dependency from you controller class. You will need to add a new binding to the your Ninject module. This binding will need to use the context to determine if it is binding the 'IRepository' to a CachedCustomerRepository instance or to the MVC Controller instance. Once you have that factored out, then Ninject will create and manage the lifetimes of both objects.
The problem is that when you create the CachedCustomerRepository
in your action method, you're just instantiating it yourself and you're not getting Ninject to instantiate it for you and subsequently inject it's dependencies.
What you should do is use constructor injection for the controller.
E.g.
public class MyController : Controller
{
public IRepository<Customer> CustomerRepo { get; protected set; }
public MyController(IRepository<Customer> customerRepo)
{
CustomerRepo = customerRepo;
}
public ViewResult Index()
{
return View(CustomerRepo.GetAll());
}
}
Your scenario is slightly confusing though, because you are injecting a IRepository<Customer>
into a IRepository<Customer>
that needs to be injected into MyController
.
精彩评论