2011-03-09 92 views
5

我是Ninject的新手,所以我确信这是我做错了,我只是不知道是什么。我在我的MVC3 Web应用程序中使用Ninject和Ninject.MVC3。这是我想要做的一个例子。Ninject不注入和抛出空引用异常

我使用Repository模式:

public interface IRepository<T> 
{ 
    T Get(object id); 
    IList<T> GetAll(); 
    void Add(T value); 
    void Update(T value); 
    void Delete(T value); 
} 

对于具体类型:

public Customer 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 

    public Customer() 
    { 
    } 
} 

现在我有2个独立的仓库,一个缓存版本,需要注射到数据库存储库:

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 void Update(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Delete(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public CachedCustomerRepository() 
    { 
    } 
} 

我建立了这样一个NinjectModule:

public class ServiceModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IRepository<Customer>>().To<CustomerRepository>(); 
    } 
} 

,我修改了AppStart的文件夹中的NinjectMVC3.cs获得创建内核时模块:

private static IKernel CreateKernel() 
{ 
    var kernel = new StandardKernel(new ServiceModule()); 
    RegisterServices(kernel); 
    return kernel; 
} 

在我的控制,我使用这样的:

public ViewResult Index() 
{ 
    IRepository<Customer> custRepo = new CachedCustomerRepository(); 
    return View(custRepo.GetAll()); 
} 

它吹在线_repository.GetAll()在我的CachedCustomerRepository

我已经设置断点,以确保该CreateKernel()正在执行和获取绑定,它是。我只是不确定为什么注射没有发生。另一方面,我不知道它是否重要,IRepository,Repositories和具体类型在一个单独的类库中,并在mvc3 web应用程序中引用。 Web应用程序和类库都提供了对Ninject的引用,并且该Web应用程序也提供了对Ninject.MVC3的引用。绑定和内核创建都在Web App中进行。

+2

+1为每个人都经历了第一次学习依赖注入的挫折。 – TheCloudlessSky 2011-03-09 19:06:25

回答

3

首先,您在控制器中调用了错误的构造函数。这个无参数的构造函数不会调用其他任何东西,这就是为什么你得到空的异常。其次,你想重构你的控制器,这样就没有直接的依赖关系。

你会想要做类似如下:

public class SomeController 
{ 
    private readonly IRepository<Customer> repo; 

    public SomeController(IRepository<Customer> repo) 
    { 
     this.repo = repo; 
    } 

    public ViewResult Index() 
    { 
     return View(this.repo.GetAll()); 
    } 
} 

这样,Ninject解决的依赖为您服务! Ninject的内核将被要求通过MVC创建一个带有IRepository<Customer>的控制器。由于Ninject有这个“绑定”,它会尝试为你实例化CustomerRepository

另外,你为什么要创建一个“CachedRepository”?我真的认为你过早地优化了这一点。老实说,你只需要一个CustomerRepository,你可以在Ninject模块中连接。

+0

我最终做的是为回购和注入创建一个属性,因为将来我将在控制器中拥有多个回购类型,并且我也为其应用了一个自定义属性。这允许我使用上下文属性绑定。 – 2011-03-09 20:06:27

+1

@亚历山大 - 虽然属性注入一定是可能的,但它通常会皱起眉头。要添加更多的存储库依赖关系,只需添加另一个构造函数参数。控制器需要什么样的上下文绑定?无论如何,我很高兴你能解决你的问题。干杯! – TheCloudlessSky 2011-03-09 20:10:43

+0

这很好知道,我还没有意识到财产注入被f upon。 – 2011-03-09 21:10:58

0

请问您有在Global.asax类继承NinjectHttpApplication

+0

我以为Ninject.MVC3 2.2.1.0如果你使用的是AppStart \ NinjectMVC3.cs – 2011-03-09 18:43:40

+0

@Alexander Kahoun,你不需要那么做:很可能;看起来它自从上次我使用Ninject以来有点太长了...... – 2011-03-09 18:52:15

+0

@Alexander - 你是对的。查看我的帖子了解详情。 – TheCloudlessSky 2011-03-09 19:07:08

0

确保您为了告诉MVC哪个解析器你要使用电话DependencyResolver.SetResolver(CreateKernel());。你可能会打电话给它,但我没有在你的文章中看到它 - 否则你的代码看起来很好。

+0

使用NinjectMVC3.cs代码自动执行此操作。 – TheCloudlessSky 2011-03-09 18:54:46

+0

是的,我发布后我发布了我的答案。我还没有尝试过新的AppStart Nuget。感谢您的权威,但现在我知道在未来:) – Buildstarted 2011-03-09 19:00:51

+0

不用担心:)新的东西使MVC集成非常顺利。 – TheCloudlessSky 2011-03-09 19:03:18

0

要获得使用国际奥委会,你应该从重构你的控制器类的CachedCustomerRepository依赖的全部好处。您需要为Ninject模块添加一个新的绑定。该绑定需要使用上下文来确定它是否将'IRepository'绑定到CachedCustomerRepository实例或MVC Controller实例。一旦你有了这个因素,Ninject就会创建并管理这两个对象的生命周期。

0

问题是,当你在你的动作方法中创建了CachedCustomerRepository时,你只是自己实例化它,并且你没有让Ninject为你实例化,然后注入它的依赖关系。

你应该做的是使用控制器的构造函数注入。

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()); 
    } 
} 

你的情况是稍显混乱,但因为你是注入IRepository<Customer>IRepository<Customer>需要注入MyController