Ninject.MVC3,将DependencyResolver传递给服务层?

时间:2011-02-28 23:47:37

标签: asp.net-mvc asp.net-mvc-3 inversion-of-control ninject ninject-2

在使用Ninject.MVC 2.2.0.3(after merge)的MVC3应用程序中,我不是直接将控制权注入控制器,而是尝试创建一个包含businesslogic的服务层并在那里注入repostories。我将ninject-DependencyResolver作为动态对象传递给服务层(因为我不想在那里引用mvc或ninject)。然后我在其上调用GetService来获取我在NinjectHttpApplicationModule中指定的绑定和生命周期的存储库。编辑:简而言之,它失败了。

在这种情况下,如何将IoC容器传递给服务层? (不同的方法也非常受欢迎。)

编辑:以下是一个示例,说明我如何理解答案和评论。

我应该避免服务定位器(anti-)pattern,而是使用依赖注入。所以我想说我想在Northwind中为产品和类别创建一个管理站点。我根据表定义创建模型,存储库,服务,控制器和视图。此时服务直接调用存储库,没有逻辑。我有功能支柱,视图显示原始数据。这些绑定是为NinjectMVC3配置的:

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

Repository-instances由ninject通过两层构造函数注入在ProductController中创建:

private readonly ProductsService _productsService;
public ProductController(ProductsService productsService)
{
    // Trimmed for this post: nullchecks with throw ArgumentNullException 
    _productsService = 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编辑操作更改为return View(_productsService.GetProductViewModel(id));,将编辑视图更改为显示下拉列表:

@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}))

一个小问题,以及我误入服务定位器的原因是,ProductController中的其他任何操作方法都不需要categories-repository。我认为除非需要,否则创建它是一种浪费和不合逻辑。我错过了什么吗?

1 个答案:

答案 0 :(得分:14)

你不需要传递周围的物体,你可以做这样的事情

// global.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库。

// service.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);
        }
    }