10

Ninject.MVC 2.2.0.3 (after merge)을 사용하는 MVC3 응용 프로그램에서 repostories를 컨트롤러에 직접 주입하는 대신 businesslogic을 포함하는 서비스 계층을 만들고 거기에 repostories를 주입하려고합니다. ninject-DependencyResolver를 동적 객체로 서비스 계층에 전달합니다 (mvc를 참조하거나 ninject를 참조하고 싶지 않기 때문에). 그런 다음 GetService를 호출하여 NinjectHttpApplicationModule에서 지정한 바인딩과 수명으로 리포지토리를 가져옵니다. 편집 : 간단히 말해서, 그것은 실패했습니다.Ninject.MVC3, 서비스 계층에 DependencyResolver를 전달 하시겠습니까?

이 경우 IoC 컨테이너를 서비스 계층에 전달할 수있는 방법은 무엇입니까? (다른 방법도 환영합니다.)

EDIT : 다음은 답변과 의견을 이해하는 방법을 보여주는 예입니다.

서비스 로케이터 (anti-)pattern을 피하고 대신 종속성 삽입을 사용해야합니다. Northwind에서 제품 및 범주에 대한 관리 사이트를 만들고 싶습니다. 필자는 테이블 정의에 따라 모델, 저장소, 서비스, 컨트롤러 및 뷰를 작성합니다. 서비스는이 시점에서 리포지토리를 직접 호출합니다. 논리가 없습니다. 필자는 기능적 기둥을 가지고 있으며 뷰는 원시 데이터를 보여줍니다. 이러한 바인딩은 NinjectMVC3 위해 구성된다

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

리포지토리 인스턴스 Ninject에 의해 생성되는 생성자 주입 2 층을 통해 상기 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; 
} 

I 현재 서비스를 분리 할 필요는 없지만 db 조롱을 준비했습니다.

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(), 
        }; 
    } 

나는 드롭 다운 보여 return View(_productsService.GetProductViewModel(id)); 및 편집 -보기로 GET 편집 액션을 변경

@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의 다른 action-methods 중 categories-repository가 필요하지 않다는 것입니다. 필요한 경우가 아니면 낭비적이고 논리적이지 않다는 생각이 듭니다. 내가 놓친 게 있니?

+1

관련 : http://stackoverflow.com/questions/2386487/is-it-better-to-create-a-singleton -to-access-unity-container-or-pass-it-through-t –

+0

감사합니다. 나는 Service Locator에 대해 설명하지 않았다. – Grastveit

답변

14

이 하나의 I 설정이

// 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 개의 파일을 가진 kernal을 만들어 내 바인딩을 모두 나눠서 찾기 쉽습니다.


내 서비스 계층 클래스에서 원하는 인터페이스 만 전달하면됩니다.이 서비스 클래스는 모든 서비스 계층 클래스를 유지하고 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 클래스를 바인딩합니다. 따라서 객체를 전달하거나 주위를 통과 할 필요가 없습니다.

.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); 
     } 
    } 
+0

생성자 삽입 및 MVC DependencyResolver에 +1. –

+0

매우 철저한 답변을 보내 주셔서 감사합니다! 따라서 서비스 내부에 자유롭게 저장소를 생성하는 대신 서비스의 모든 메소드가 동일한 저장소를 사용하는지 또는 불필요한 저장소를 만드는 것에 대해 걱정하지 않아도됩니까? – Grastveit

+0

이 응답에서 사용자 지정 DependencyResolver 및 Application_Start를 사용하지 마십시오. Ninject.MVC3와 함께있어! 위에서 설명한대로 생성자 삽입을 구현하기 만하면됩니다. 설명 된대로 서비스 탐지기로 Ninject를 사용할 필요가 없습니다. –

관련 문제