2013-01-07 2 views
1

다음 시나리오에서 저를 교정하십시오. (질문 끝남)ISession을 저장소에 정확하게 주입하는 방법은 무엇입니까?

(비슷한 질문을했는데 정리가 안되었습니다.이 질문을 정확한 대답으로 대답 할 수있는 범위로 요약했습니다.)

ORM으로 nhibernate를 사용하여 여러 레이어가있는 웹 응용 프로그램을 개발 중입니다. 상기 레이어

  1. 모형 층
  2. 저장소 계층
  3. 서비스 계층
  4. UI 계층

, 클래스 및 인터페이스는 아래와 같이 배치를 다음과 같이 내 층 구조이다.

ProductController.cs (UI 계층)

public class ProductController : Controller 
{ 
    ProductServices _ProductServices; 
    NHibernate.ISession _Session; 

    public ProductController() 
    { 
     _Session = SessionManager.GetCurrentSession(); 

     _ProductServices = new ProductServices(
      new ProductRepository(), _Session); 
    } 
    // Cont.. 
} 

ProductServices.cs (서비스 계층)

public class ProductServices : IProductServices 
{ 
    protected IProductRepository _ProductRepository; 
    protected NHibernate.ISession _Session; 

    public ProductServices(IProductRepository productRepository, 
     NHibernate.ISession session) 
    { 
     _ProductRepository = productRepository; 
     _Session = session; 
     _ProductRepository.SetSession(_Session); 
    } 

    // cont... 
} 

ProductRepository.cs (리포지토리 레이어)

public class ProductRepository : IProductRepository 
{ 
    NHibernate.ISession _Session; 

    public void SetSession(NHibernate.ISession session) 
    { 
     _Session = session; 
    } 

    public IEnumerable<Product> FindAll() 
    { 
     return _Session.CreateCriteria<Product>().List<Product>(); 
    } 

    //cont.. 
} 

UI 레이어에서 세션 당 요청을 만들고 클래스 생성자의 도움을 받아 서비스 레이어에 삽입합니다. 그런 다음 방법의 도움으로 저장소 세션을 설정하십시오.

_Session을 생성자로 직접 리포지토리에 전달하면 서비스 계층 아래에서 해당 컨트롤을 제어 할 수 없습니다. 또한 webservice 레이어를 사용하기위한 향후 확장 계획이 있습니다.

** 코드가 인 각각의 메서드를 동일한 코드를 반복 할 때 각 메서드에 if(_Session==null) 작성하지 않고도 이미 설정된 ProductRepository 클래스에서 보장 할 수있는 방법이 있습니까?

** 위의 패턴이 잘못되면이 목표를 달성하기위한 올바른 방법을 보여주십시오.

+0

[여기에 몇 가지 일반적인 조언이 있습니다] (http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why) 당신의 세션을 위해 선택할 라이프 스타일. – Steven

+0

이것은 단지 주석 일뿐입니다. nhibernate는 이미 저장소/작업 단위 패턴을 수행하고 있으며 코드는 쓸모없는 계층을 추가하는 것입니다. http://ayende.com/blog/153701/ask-ayende-life-without-repositories-are-they-worth-living –

답변

5

. ProductService에 생성자 주입 패턴을 적용 했으므로 확실히 갈 수 있습니다. 반면에 ProductController에 종속성을 삽입하지는 않지만 해당 클래스는 정적 클래스 (Service Locator 방지 패턴)를 통해 이러한 종속성 중 하나를 요청하고 ProductServices 클래스를 만듭니다.덕분에이 클래스는 테스트하기가 어렵고 응용 프로그램을 덜 유연하고 유지하기 쉽게 만듭니다. 여러 장소에서 사용되었을 때 ProductServices 클래스의 사용을 쉽게 변경, 장식 또는 가로 챌 수 없기 때문입니다.

ProductServices의 종속성에 대해 생성자 삽입을 올바르게 사용하더라도 ProductResopistory에 생성자 주입 패턴을 적용하는 대신 해당 종속성을 제품 저장소로 전달합니다.

이 목표를 달성하기위한 올바른 방법을 보여주십시오.

올바른 방법은 모든 곳에서 생성자 주입 패턴을 적용하는 것입니다. 이렇게하면 코드는 다음과 같이 표시됩니다.

public class ProductController : Controller 
{ 
    private ProductServices _ProductServices; 

    public ProductController(ProductServices services) 
    { 
     _ProductServices = services; 
    } 
    // Cont.. 
} 

public class ProductServices : IProductServices 
{ 
    private IProductRepository _ProductRepository; 

    public ProductServices(
     IProductRepository productRepository) 
    { 
     _ProductRepository = productRepository; 
    } 
    // cont... 
} 

public class ProductRepository : IProductRepository 
{ 
    private ISession _Session; 

    public ProductRepository (ISession session) 
    { 
     _Session = session; 
    } 

    public IEnumerable<Product> FindAll() 
    { 
     return _Session 
      .CreateCriteria<Product>().List<Product>(); 
    } 
    //cont.. 
} 

각 클래스가 자체적으로 사용하는 종속성 만 사용하는 방법을 확인하십시오. 따라서 ProductControllerProductServicesISession에 의존하지 않습니다. (ProductRepoistory에만 ISession이 필요하다는 가정하에 작성되었습니다.) 수업의 관점에서 볼 때 모든 것이 훨씬 간단합니다.

실제로 여기에서 문제가 해결 되었습니까? 우리는 모든 클래스를 종속 그래프 위로 연결하는 문제를 방금 옮긴 것처럼 보입니다. 예, 우리는 문제를 옮겼습니다. 그리고 이것은 좋은 일입니다. 이제는 각 클래스를 개별적으로 테스트하고 따라하기 쉽고 응용 프로그램 전체를 유지 관리 할 수 ​​있습니다.

그러나 어딘가에 ProductController을 만들어야합니다.

new ProductController(
    new ProductServices(
     new ProductRepository(
      SessionManager.GetCurrentSession()))); 

정상적인 구성에서 ASP.NET MVC는 컨트롤러 클래스를 만들고이를 수행하는 데 기본 생성자가 필요합니다. 생성자 주입 (반드시해야하는)을 사용하여 컨트롤러를 연결하려면이 작업을 수행하기 위해 '특별'작업을 수행해야합니다.

ASP.NET MVC를 사용하면 ControllerFactory 클래스를 재정의 할 수 있습니다. 이를 통해 컨트롤러 인스턴스를 작성하는 방법을 결정할 수 있습니다. 그러나 응용 프로그램이 커지기 시작하면 종속성 그래프를 손으로 만들 때 매우 빨리 처리됩니다 (마지막 예제에서와 같이). 이 경우 Dependency Injection 프레임 워크를 사용하는 것이 훨씬 더 좋습니다. 대부분은 ASP.NET MVC와 통합 할 수있는 기능/패키지를 포함하고 있으며 MVC 컨트롤러에 생성자 삽입을 자동으로 사용할 수 있습니다.

아직 완료 되었습니까? 글쎄 ... 우리가 여기 있니? 내 두뇌에 깃발을 들여 놓은 디자인이 하나 있습니다. 시스템에 ProductServices이라는 클래스가 있습니다. 자연스러운 추측이지만, Services이라는 이름은 해당 제품 내부의 모든 비즈니스 관련 업무를 래핑 한 것처럼 보입니다. 시스템 크기, 팀 구성원 수 및 변경해야하는 사항에 따라 문제가 발생할 수 있습니다. 예를 들어, 시스템에 유지 보수가 가능한 방식으로 교차로 관련 문제 (예 : 로깅, 유효성 검사, 프로파일 링, 트랜잭션 관리, 내결함성 향상)를 효과적으로 적용하는 방법은 무엇입니까?

모든 작업을 단일 ProductServices 클래스로 래핑하는 대신 각 비즈니스 트랜잭션/사용 사례에 고유 한 클래스를 지정하고 모든 클래스에 동일한 (일반) 인터페이스를 적용 해보십시오. 이 설명은 다소 모호하지만, 크고 큰 시스템의 유지 보수성을 향상시키는 좋은 방법입니다. 자세한 내용은 here을 참조하십시오.

+1

와우 .. 큰 설명에 감사드립니다. 나를 통해 그것을 보내주십시오. – BlueBird

0

Autofac과 같은 종속성 주입 컨테이너를 사용하여 세션을 인스턴스화하고 세션의 수명을 관리 할 수 ​​있습니다. 세션을 인스턴스화하는 책임을 Autofac에 맡기고 단순히 종속성이 필요한 클래스에 ISession 인터페이스를 삽입하십시오. 이 게시물에서보세요 : Managing NHibernate ISession with Autofac

또한 MVC3와 Autofac를 구성하는 방법에 대한 유용한 위키 페이지를 찾을 수 있습니다 : 당신이 나에게 조금 깜짝 놀라게하는 일 http://code.google.com/p/autofac/wiki/MvcIntegration3

+0

은 주목할만한 것 같습니다. 내가 확인 할게. – BlueBird

관련 문제