2010-02-01 2 views
2

우리는 설정 파일에 성의 윈저 구성 요소를 선언했습니다. 내부의 일부 구성 요소는 다른 구성 요소의 서비스를 필요로 할 수 있습니다.캐슬 구성품은 주문을 처리합니다.

문제는 응용 프로그램이 닫히고 컨테이너가 처리 중일 때입니다. 시작/삭제 가능한 구성 요소 (A)의 Dispose()/중지() 중에 다른 구성 요소 (B)의 서비스가 필요한 경우 ComponentNotFoundException가 발생합니다. 그때까지 B는 이미 컨테이너에서 제거됩니다.

app config 파일의 구성 요소 선언 순서가 중요하다는 것을 알고 있습니다. 그리고 reodering A와 B는 문제를 해결합니다.

구성 요소가 폐기되는 순서에 영향을주는 더 좋은 방법이 있습니까?

편집 :

class Program 
{ 
    static void Main() 
    { 
     IoC.Resolve<ICriticalService>().DoStuff(); 
     IoC.Resolve<IEmailService>().SendEmail("Blah"); 
     IoC.Clear(); 
    } 
} 

internal class CriticalService : ICriticalService, IStartable 
{ 
    public void Start() 
    {} 

    public void Stop() 
    { 
     // Should throw ComponentNotFoundException, as EmailService is already disposed and removed from the container 
     IoC.Resolve<IEmailService>().SendEmail("Stopping"); 
    } 

    public void DoStuff() 
    {} 
} 

internal class EmailService : IEmailService 
{ 
    public void SendEmail(string message) 
    { 
     Console.WriteLine(message); 
    } 

    public void Dispose() 
    { 
     Console.WriteLine("EmailService Disposed."); 
     GC.SuppressFinalize(this); 
    } 
} 

internal interface ICriticalService 
{ 
    void DoStuff(); 
} 

internal interface IEmailService : IDisposable 
{ 
    void SendEmail(string message); 
} 

public static class IoC 
{ 
    private static readonly IWindsorContainer _container = new WindsorContainer(new XmlInterpreter()); 

    static IoC() 
    { 
     _container.AddFacility<StartableFacility>(); 
     // Swapping the following 2 lines resolves the problem 
     _container.AddComponent<ICriticalService, CriticalService>(); 
     _container.AddComponent<IEmailService, EmailService>(); 
    } 

    public static void Clear() 
    { 
     _container.Dispose(); 
    } 

    public static T Resolve<T>() 
    { 
     return (T)_container[typeof(T)]; 
    } 
} 

참고 : 어떻게 용기에 삽입하는 구성 요소의 순서를 교환 코드의 주석을 참조하십시오 여기 ComponentNotFoundException가 발생합니다 샘플 코드를 제공 주석의 요청에 따라 문제를 해결합니다.

+0

Start/Stop은 StartableFacility에서 제공하는 두 가지 문제이며 Disposable은 원칙적으로 시작/중지와 관련이없는 또 다른 문제입니다. StartableFacility는 구성 요소를 "해제"할 때 실행되는 첫 번째 Stop 관심사를 보장합니다. Dispose()가 Stop() 전에 실행된다고 말하면 버그처럼 보입니다. 우리에게 몇 가지 코드를 보여줄 수 있습니까? 아마도 테스트 케이스를 게시 할 수 있습니까? –

+1

귀하의 의견을 보내 주셔서 감사합니다. Container가 삭제되면 시작 가능한 각 구성 요소를 반복하고 각 Stop(), Dispose()를 호출하여 Container에서 제거합니다. 나는 그것이 모든 시작품에 대해 Stop()을 먼저 호출해야하며, 그 다음에 폐기하고 Container에서 제거해야한다고 예상 할 것이다. –

+1

예, 컨테이너는 시작 가능한 각 구성 요소를 반복하고 각 Stop(), Dispose()를 호출합니다. 이는 동작입니다. ComponentNotFoundException을 throw하는 테스트 케이스를 게시 할 수 있습니까? –

답변

5

정적 IoC 클래스를 사용하면 실제로 컨테이너를 서비스 검색 자로 사용하므로 종속성 주입의 이점 대부분을 잃어 버리게됩니다.

적절한 주입이 없으면 Windsor는 CriticalService - IEmailService 종속성에 대해 알지 못하므로 올바른 폐기 순서를 보장 할 수 없습니다.

이 의존성이 명시 적으로 만들기 위해 리팩토링 경우

는 윈저가 올바른 순서로 구성 요소를 처분 :

internal class CriticalService : ICriticalService, IStartable 
{ 
    private readonly IEmailService email; 

    public CriticalService(IEmailService email) { 
     this.email = email; 
    } 
... 
} 

Here's how it would look을 리팩토링 후처럼.

+0

도움을 주셔서 감사합니다. 나는 생성자 의존성에 대한 당신의 의견에 완전히 동의한다. 그러나 그것은 단지 샘플이었을 뿐이며, 우리 시스템은 훨씬 더 크고 복잡합니다. 달성하기가 쉽지 않지만 우리는이 영역을 리펙토링하려고 노력할 것입니다. StartableFacility에 관해서는 샘플 코드에 추가하는 것을 잊어 버렸습니다 (설정 파일에 남겨 둡니다). 업데이트 된 샘플 코드를 참조하십시오. 시작 가능한 시설에서는 작동하지 않습니다. –

+0

2.1.1 및 StartableFacility - ComponentNotFoundException로 테스트 됨 –

+0

그런데, Ayende의이 패턴에 대한 귀하의 의견은 어떻습니까? http://ayende.com/Blog/archive/2006/07/30/IoCAndFluentInterfaces.aspx –

2

개인적으로, Dispose()이 특정 순서로 호출되어야하는 시스템은 설계에 결함이 있다고 개인적으로 생각합니다.

Dispose()항상이어야합니다. 이 오류는 폐기 후 구성 요소를 사용한 다음에 ObjectDisposedException이 가장 적합한 경우에만 발생해야합니다. 이와 같은 경우에는 구성 요소를 다시 작성하여 Dispose() 메서드에서 다른 구성 요소를 사용하지 않도록합니다 (실제로는 각 구성 요소의 자체 비공개 리소스를 정리해야합니다). 이렇게하면이 문제가 완전히 제거됩니다.

+2

한편으로는 당신이 옳다. 나는 모든 Startable 구성 요소를 반복하고, 내가 원하는 순서대로 Stop()을 호출 한 다음 Castle.Windsor.IWindsorContainer.Dispose()를 호출해야한다. 반면에, Castle 프레임 워크는 Dispose() 메소드를 제공 할 때 내 대신에이를 수행 할 것으로 기대합니다. –

+0

"Windsor의 고유 한 기능 중 하나는 그것이 당신을 위해 생성 한 객체의 라이프 사이클을 관리한다는 것입니다. 다른 것들 중에서도 그것이 인스턴스화하는 모든 일회용 객체를 처리한다는 것입니다." –

+1

정말 그걸로 아무 상관이 없다. 그들은 당신의 구성 요소에 대해 Dispose를 호출 할 것이지만 Dispose()가 호출되면 다른 구성 요소에 의존해서는 안됩니다. 처리 순서는 중요하지 않아야합니다 ... –

관련 문제