2011-11-30 2 views
1

나는 길이에 사과하고 이것에 약간 응답이다는 것을 나는 알고있다 그러나 나는 많은 것을 수색하고 맞은 해결책을 찾아 내지 않았다, 이렇게 저와 견뎌주십시오.IoC 콘테이너 합병증을 가진 C# ASP.NET 의존성 주입

레거시 응용 프로그램이 ASP.NET 웹 양식에서 DI를 사용하기위한 프레임 워크를 만들려고합니다. 아마도 성 윈저 을 프레임 워크로 사용할 것입니다.

이러한 레거시 응용 프로그램은 일부 장소에서 부분적으로 MVP 패턴을 사용합니다.

발표자는 다음과 같이 보일 것입니다 :

class Presenter1 
{ 
    public Presenter1(IView1 view, 
     IRepository<User> userRepository) 
    { 
    } 
} 

를 이제 ASP.NET 페이지가 같은 것을 보일 것 다음에 다음과 같이 내가 발표자를 인스턴스화 할 DI를 사용하기 전에

public partial class MyPage1 : System.Web.UI.Page, IView1 
{ 
    private Presenter1 _presenter; 
} 

을 페이지의 onInit :

protected override void OnInit(EventArgs e) 
{ 
    base.OnInit(e); 
    _presenter = new Presenter1(this, new UserRepository(new SqlDataContext())); 
} 

을 그래서 지금은 DI를 사용하고 싶습니다.

먼저 내 페이지 구성을 무시하기 위해 핸들러 팩토리를 만들어야합니다. 내가 도움이 정말 좋은 답을 발견 How to use Dependency Injection with ASP.NET Web Forms

이제

내가 쉽게 마크 시먼로 내 조성 루트에 내 컨테이너를 설정할 수는 Global.asax에 를 사용하는 것이 좋습니다 (이 정적 컨테이너를 만들 수 있지만 그해야 함을 의미 안전하고 밀봉 스레드 수) 추가 등록을 추가 할 지금

내가 가서

public MyPage1() : base() 
{ 
} 

public MyPage1(Presenter1 presenter) : this() 
{ 
    this._presenter = presenter; 
} 

이제 우리는 첫 번째 문제로 실행 페이지에서 생성자 주입을 선언 할 수 있습니다 할 수 없습니다, 나는 순환 종속성이 . Presenter1은 IView1에 의존하지만 페이지는 발표자에 따라 다릅니다.

원형 종속성이있을 때 설계가 잘못되었다는 것을 알게되었습니다. 처음에는 Presenter 디자인이 잘못되었다고 생각합니다. View에 대한 생성자에 의존하여이 코드를 MVP 구현을 많이 보아 말할 수 있습니다.

일부는 Presenter1이 속성이되는 디자인 페이지를 변경 한 후 이벤트의 무리를 통해 간단하게 묶기 후 일부는 심지어 완전히 발표자 종속성을 제거하는 제안 할 수 있습니다 재산권 주입

public partial class MyPage1 : System.Web.UI.Page, IView1 
{ 
    [Dependency] 
    public Presenter1 Presenter 
    { 
     get; set; 
    } 
} 

를 사용하여 제안 할 수 있습니다 그러나 이것은 이 아니고 내가 원했던 디자인이 아니라 솔직히 왜 내가이 변화를 수용해야하는지 알지 못한다.

어쨌든 상관없이 제안의 또 다른 문제는 존재 :

를 핸들러 공장은 타입이 사용할 수있는 페이지 요청 (NOT보기 인터페이스)지면 : 지금이 유형을 사용

Type pageType = page.GetType().BaseType; 

을 IOC의 및 종속성을 통해 페이지를 해결할 수 있습니다

container.Resolve(pageType) 

이를 다음 Presenter1라는 속성이 있음을 알고 그것을 주입 할 수 있습니다. 그러나 Presenter1에는 IView1이 필요하지만 컨테이너를 통해 IView1을 확인하지 못했습니다. 따라서 컨테이너는 컨테이너 외부에서 생성 된 것처럼 방금 생성 한 핸들러 팩토리를 콘크리트 인스턴스에 제공하기 위해 을 알 수 없습니다. 을 따라서 핸들러 팩토리 페이지 해결 여기서 : 이것은 또 다른 문제를 야기

private void InjectDependencies(object page) 
{ 
    Type pageType = page.GetType().BaseType; 
    // hack 
    foreach (var intf in pageType.GetInterfaces()) 
    { 
     if (typeof(IView).IsAssignableFrom(intf)) 
     { 
      _container.Bind(intf,() => page); 
     } 
    } 

    // injectDependencies to page...  
} 

을, 성 윈저와 같은 대부분의 용기가 당신을 허용하지 않습니다

그래서 우리는 우리의 핸들러 팩토리를 해킹하고 뷰 인터페이스를 교체해야 이 인터페이스 을 지금 가리키는 인스턴스에 등록하십시오. 또한 컨테이너가 Global.asax에 등록되어 있으면이 시점에서만 컨테이너를 읽어야하므로 에 스레드로부터 안전하지 않습니다.

다른 해결책은 각 웹 요청에서 컨테이너를 다시 작성하는 함수를 만든 다음 인스턴스에 설정되지 않은 경우 컨테이너에 IView가 포함되어 있으면 을 확인하는 것입니다. 그러나 이것은 낭비가되어 제안 된 사용에 반대합니다.

다른 솔루션은 IPresenterFactory라는 특별한 공장을 만들고 페이지 생성자에서 종속성을 넣어하는 것입니다

public MyPage1(IPresenter1Factory factory) : this() 
{ 
    this._presenter = factory.Create(this); 
} 

문제는 당신이 지금 할 각 발표자의 공장을 만들 필요가있는 더 우아한 해결책을

class Presenter1Factory : IPresenter1Factory 
{ 
    public Presenter1Factory(Container container) 
    { 
     this._container = container; 
    } 
    public Presenter1 Create(IView1 view) 
    { 
     return new Presenter1(view, _container.Resolve<IUserRepository>,...) 
    } 
} 

이 디자인은 또한 복잡하고 복잡한 이상의 것, 어떤 일이 있습니까 아이디어 : 다른 종속성을 해결하기 위해 컨테이너 에 전화를?

답변

1

아마도 나는 당신의 문제를 오해하지만,이 솔루션은 나에게 매우 간단 보인다 다음 Presenter1에 속성에 IView을 촉진 :

class Presenter1 
{ 
    public Presenter1(IRepository<User> userRepository) 
    { 
    } 

    public IView1 View { get; set; }    
} 

이 같은 뷰에 발표자를 설정할 수 있습니다이 방법을 :

다음과 같이
public Presenter1 Presenter { get; set; } 

public MyPage1() 
{ 
    ObjectFactory.BuildUp(this); 
    this.Presenter.View = this; 
} 

또는 속성 주입없이 , 당신은 그것을 할 수 있습니다 :

private Presenter1 _presenter; 

public MyPage1() 
{ 
    this._presenter = ObjectFactory.Resolve<Presenter1>(); 
    this._presenter.View = this; 
} 

Page 클래스의 생성자 삽입은 실제로 작동하지 않습니다. 완전 신뢰 (as this article shows)로 작업 할 수는 있지만 부분 신뢰는 실패합니다. 따라서 컨테이너를 호출해야합니다.

모든 DI 컨테이너는 초기화 단계 후에 수동으로 등록을 수동으로 추가하지 않고 스레드가 안전하더라도 (초기화 후 형식을 등록하는 것을 금지하는 some containers조차도) 일부 컨테이너의 경우 등록을 직접 추가하지 않는 한 모든 DI 컨테이너는 스레드로부터 안전합니다. 대부분의 컨테이너가 지원하는 등록되지 않은 유형 확인을 제외하고는이 작업을 수행 할 필요가 없습니다. 그러나 Castle과 함께 모든 구체적인 유형을 등록해야합니다. 즉, 해결하기 전에 Presenter1에 대해 알아야한다는 의미입니다. 이것을 등록하거나이 동작을 변경하거나 기본적으로 구체적인 유형을 확인할 수있는 컨테이너로 이동하십시오.

+0

안녕하세요, 스티븐, 답변 해 주셔서 감사합니다. 문제를 올바르게 이해했습니다. 귀하의 솔루션이 작동하고 아마도 최고의 솔루션입니다. 나는 생성자 주입과 함께 작동 시키려고 노력했다. 뷰를 속성으로 만들면 캡슐화가 조금씩 깨져 보입니다. 의도하지 않았던 것처럼 수정할 수있는 공개로 표시되지만 개발자가 각 페이지에서 설정해야하는 추가 속성이 있습니다. 그러나 이것이 유일한 방법 인 것처럼 보입니다. 링크에 대한 훌륭한 블로그 게시물 덕분입니다. – Andre