asp.net-mvc - Ninject.MVC3,将 DependencyResolver 传递给服务层?

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

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

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

编辑 :这是一个例子来说明我如何理解答案和评论。

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

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

存储库实例由 ninject 通过两层构造函数注入(inject)在 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));和编辑 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 个文件制作了一个内核来拆分我所有的绑定(bind),因此很容易找到。

在我的服务层类中,您只需传入所需的接口(interface)。这个服务类在它自己的项目文件夹中,我保存了我所有的服务层类,并且没有对 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>();


        }

    }       

看看我如何将接口(interface)绑定(bind)到 repo。现在每次看到该接口(interface)时,它都会自动将 Repo 类绑定(bind)到它。所以你不需要传递对象或任何东西。

您无需担心将 .dll 导入您的服务层。例如,我的服务类在他们自己的项目文件中,您在上面看到的所有内容(当然是服务类)都在我的 webui 项目中(我的 View 和 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);
        }
    }

关于asp.net-mvc - Ninject.MVC3,将 DependencyResolver 传递给服务层?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5148959/

相关文章:

asp.net-mvc - 使用 IIS 进行 ASP.NET MVC 调试时设置虚拟目录

asp.net-mvc - MVC 3 要求 System.Web 版本 2.0.0.0 (System.Web.UI.Controls) : Is this a compiler bug?

c# - 数据注释如何工作?

asp.net-mvc - ASP.NET MVC3 中的随机 session 超时

java - 我可以向第三方 bean 注入(inject)属性吗?

c# - IoC 或依赖注入(inject)框架以支持 MVVM 框架

c# - Context.User 在 Asp.net MVC 应用程序中通过 windows auth 在 Application_AuthenticateRequest 中为 NULL

c# - 如何从 HttpPostedFileBase file.InputStream 获取 SHA1 和 MD5 校验和

c# - 使用 Windows 服务手动实现 IoC

c# - 使用 ToList() 与使用 IList 从存储库返回 IEnumerable