2011-03-09 43 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