在使用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。我认为除非需要,否则创建它是一种浪费和不合逻辑。我错过了什么吗?
答案 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);
}
}