在这种情况下,IoC容器如何传递到服务层? (不同的方法也很受欢迎.)
编辑:这是一个例子来说明我如何理解答案和意见.
我应该避免服务定位器(anti-)pattern,而是使用依赖注入.所以我想说,我想为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; }
我现在没有必要去分离服务,但已经准备好嘲笑数据库了.
要在“产品/编辑”中显示类别的下拉列表,我将创建一个除了产品之外的类别的viewmodel:
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编辑操作以返回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中的其他操作方法都不需要category-repository.我觉得创建它是一种浪费,不合逻辑,除非需要.我错过了什么吗?
解决方法
// 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项目(我的views和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); } }