Asp.net-Mvc

Ninject.MVC3,將 DependencyResolver 傳遞給服務層?

  • July 16, 2011

在具有 Ninject.MVC 2.2.0.3 (合併後)的 MVC3 應用程序中,我沒有將儲存庫直接注入控制器,而是嘗試創建一個包含業務邏輯的服務層並在那裡註入儲存庫。我將 ninject-DependencyResolver 作為動態對像傳遞給服務層(因為我不想在那裡引用 mvc 或 ninject)。然後我在其上呼叫 GetService 以獲取具有我在 NinjectHttpApplicationModule 中指定的綁定和生命週期的儲存庫。編輯:簡而言之,它失敗了。

在這種情況下,如何將 IoC 容器傳遞給服務層?(也非常歡迎不同的方法。)

編輯:這是一個例子來說明我如何理解答案和評論。

我應該避免使用服務定位器(反)模式,而是使用依賴注入。因此,假設我想在 Northwind 中為產品和類別創建一個管理站點。我根據表定義創建模型、儲存庫、服務、控制器和視圖。此時服務直接呼叫儲存庫,沒有邏輯。我有功能支柱,視圖顯示原始數據。這些綁定是為 NinjectMVC3 配置的:

   private static void RegisterServices(IKernel kernel)
   {
       kernel.Bind<ICategoryRepository>().To<CategoryRepository>();
       kernel.Bind<IProductRepository>().To<ProductRepository>();
   }       

儲存庫實例由 ninject 通過兩層建構子注入在 ProductController 中創建:

private readonly ProductsService _productsService;
public ProductController(ProductsService productsService)
{
   // Trimmed for this post: nullchecks with throw ArgumentNullException 
   _productsService = productsService;
}

和產品服務:

protected readonly IProductRepository _productRepository;
public ProductsService(IProductRepository productRepository)
{
   _productRepository = productRepository;
}

我現在不需要解耦服務,但已經準備好模擬數據庫了。

為了在 Product/Edit 中顯示類別的下拉列表,我創建了一個 ViewModel,其中包含除 Product 之外的類別:

public class ProductViewModel
{
   public Product Product { get; set; }
   public IEnumerable<Category> Categories { get; set; }
}

ProductsService 現在需要一個 CategoriesRepository 來創建它。

   private readonly ICategoryRepository _categoryRepository;

   // Changed constructor to take the additional repository
   public ProductsServiceEx(IProductRepository productRepository, 
       ICategoryRepository categoryRepository)
   {
       _productRepository = productRepository;
       _categoryRepository = categoryRepository;
   }

   public ProductViewModel GetProductViewModel(int id)
   {
       return new ProductViewModel
                  {
                      Product = _productRepository.GetById(id),
                      Categories = _categoryRepository.GetAll().ToArray(),
                  };
   }

我將 GET Edit-action 更改為return View(_productsService.GetProductViewModel(id));和 Edit-view 以顯示下拉列表:

@model Northwind.BLL.ProductViewModel
...
   @Html.DropDownListFor(pvm => pvm.Product.CategoryId, Model.Categories
       .Select(c => new SelectListItem{Text = c.Name, Value = c.Id.ToString(), Selected = c.Id == Model.Product.CategoryId}))

一個小問題,也是我在 Service Locator 上誤入歧途的原因,是 ProductController 中的其他操作方法都不需要類別儲存庫。我覺得除非需要,否則創建它是一種浪費且不合邏輯。我錯過了什麼嗎?

你不需要傳遞對像你可以做這樣的事情

// 全域.aspx


protected void Application_Start()
       {
           // Hook our DI stuff when application starts
           SetupDependencyInjection();
       }

       public void SetupDependencyInjection()
       {         
           // Tell ASP.NET MVC 3 to use our Ninject DI Container
           DependencyResolver.SetResolver(new NinjectDependencyResolver(CreateKernel()));
       }

       protected IKernel CreateKernel()
       {
           var modules = new INinjectModule[]
                             {
                                new NhibernateModule(),
                                new ServiceModule(),
                                new RepoModule()
                             };

           return new StandardKernel(modules);
       }

所以在這個我設置了所有的 ninject 東西。我用 3 個文件製作了一個核心來拆分我所有的綁定,因此很容易找到。


在我的服務層類中,您只需傳入所需的介面。這個服務類在它自己的項目文件夾中,我保存了我所有的服務層類,並且沒有對 ninject 庫的引用。

// 服務.cs

   private readonly IRepo repo;
   // constructor
       public Service(IRepo repo)
       {
           this.repo = repo;
       }

這就是我的 ServiceModule 的樣子(在 global.aspx 中創建的內容)

// ServiceModule()
public class ServiceModule : NinjectModule
   {
       public override void Load()
       {

          Bind<IRepo>().To<Repo>();


       }

   }       

看看我如何將介面綁定到 repo。現在每次看到該介面時,它都會自動將 Repo 類綁定到它。所以你不需要傳遞對像或任何東西。

您無需擔心將 .dll 導入您的服務層。例如,我的服務類在他們自己的項目文件中,您在上面看到的所有內容(當然是服務類)都在我的 webui 項目中(我的視圖和 global.aspx 所在的位置)。

Ninject 不關心服務是否在不同的項目中,因為我猜它在 webui 項目中被引用。

編輯

忘了給你 NinjectDependecyResolver

  public class NinjectDependencyResolver : IDependencyResolver
   {
       private readonly IResolutionRoot resolutionRoot;

       public NinjectDependencyResolver(IResolutionRoot kernel)
       {
           resolutionRoot = kernel;
       }

       public object GetService(Type serviceType)
       {
           return resolutionRoot.TryGet(serviceType);
       }

       public IEnumerable<object> GetServices(Type serviceType)
       {
           return resolutionRoot.GetAll(serviceType);
       }
   }

引用自:https://stackoverflow.com/questions/5148959