2013-02-14 4 views
1

내 ASP.NET MVC 프로젝트에서 Unity를 사용하여 종속성 삽입을 구현하려고 시도하고 순환 참조를 피하는 방법에 대한 조언이 필요합니다.Unity - 순환 참조를 피하는 방법은 무엇입니까?

제 업무에서 우리는 응용 프로그램의 개별 서비스마다 싱글 톤을 반환하는 서비스 로케이터 패턴을 구현했습니다. 유니티는 바람이었다 사용하여 DI 설정

private ServiceWrapper _services = new ServiceWrapper(); 

public ActionResult Index() 
{ 
    List<Product> products = _services.Product.GetProducts(); 
    return View(products); 
} 

:

public class ServiceWrapper 
{ 
    private UserService _userService; 
    private ProductService _productService; 


    public UserService User 
    { 
    if(_userService == null) 
    { 
     _userService = new UserService(); 
    } 
    return _userService; 
    } 

    public ProductService Product 
    { 
    if(_productService == null) 
    { 
     _productService = new ProductService(); 
    } 
    return _productService; 
    } 
} 

그런 다음 컨트롤러에서, 당신은 쉽게 같은 방법을 ServiceWrapper를 인스턴스화하고 호출하여 모든 서비스에 액세스 할 수 있습니다. 그래서 같은 위해 Application_Start() (의 Global.asax)에서 컨테이너를 작성 :

var container = new UnityContainer(); 
container.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager()); 
container.RegisterType<IProductService, ProductService>(new ContainerControlledLifetimeManager()); 
container.RegisterType<IServiceWrapper, ServiceWrapper>(new ContainerControlledLifetimeManager()); 
DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 

ServiceWrapper는 싱글로서 등록된다. 그리고 생성자 주입을 다음과 같이 구현했습니다 :

public class ProductController: Controller 
{ 
    private IServiceWrapper _services; 

    public ProductController(IServiceWrapper services) 
    { 
    _services = services; 
    } 

    public ActionResult Index() 
    { 
    List<Product> products = _services.Products.GetProducts(); 
    return View(products); 
    } 

그 것이 아름답게 작동했습니다. 그러나 그 때 나는 문제를 건너왔다.

우리는 당신이 쉽게과 같이, 다른 내에서 다른 서비스에 액세스 할 수 있도록 또한 ServiceWrapper를 포함하는 속성을 가지고 모든 서비스를 원하는 :

public class ProductService 
{ 
    private IServiceWrapper _services; 

    public ProductService(IServiceWrapper services) 
    { 
    _services = services; 
    } 

    public IServiceWrapper Services { get { return _services; } } 
} 

을하지만 난의 생성자 주입을 구현하는 경우 개별 서비스에서 ServiceWrapper를 사용하면 순환 참조로 인해 stackoverflow 예외가 발생합니다.

유니티는 순환 참조를 지원하지 않는다고 읽었습니다. 이것 주위에 (단단한) 방법이 있나. 아니면 다른 아키텍처를 구현해야합니까? 그렇다면 솔루션을 추천 해 주시겠습니까?

+0

아니요 아니요. imho 서비스 로케이터는 LOB 응용 프로그램에서 사용하면 안됩니다. 많은 서비스를 사용하여 수업을 찾으면 일반적으로 너무 크며 리팩토링해야합니다. 래퍼를 사용하면 앞으로 유지 보수 문제 만 해결할 수 있습니다. – jgauffin

+0

[Clean Code Talks : Singletons and Global State] (http://www.youtube.com/watch?v=-FRm3VPhseI) –

+0

Mark Seeman의 [Dependency Injection in .NET]에 대한 책 (http : //www.manning .com/seemann /). 특히 패턴 및 반 패턴 섹션을 읽을 가치가 있습니다. –

답변

1

일반적으로 이렇게하는 방법은 필요한 서비스를 선언하고 ctor-injected하도록하는 것입니다. 모든 것을 포함하고있는 "ServiceWrapper"를 삽입하지 마십시오. 필요한 것을 주사하십시오. 컨테이너가 귀하의 유형을 구축하기 때문에 서비스 제공에 대해 걱정할 필요가 없습니다. 그들은 거기에있을 것입니다.

개발 워크 플로우는 종종 이렇게되면 :의 ctor를 생성 Alt + 기능 :

  1. 가 ReSharper에서를 사용하여의 ctor을 다시
  2. ctor에 기존의 삭제 새로운 의존성 주입 필드
  3. 를 추가합니다.
+0

음. 새로운 멤버 필드'IMyNewServer _newService'를 추가하고 필드 이름을 ALT + ENTER로 입력하여 기존 생성자에 삽입 (resharper 사용)해야합니다. 덜 할;) 그리고 당신은 초기화의 나머지 부분을 계속 지켜야합니다. – jgauffin

+0

@jgauffin 맞아.나는 또한 그렇게한다는 것을 잊었습니다. 그것은 단지 근육 기억이고, 의식하기 어렵습니다. – usr