2016-06-04 5 views
1
public class IMessageHandler<T> { 
    void Handle(T message); 
} 

다른 이름 공간에 동일한 유형의 IMessageHandler 구현이 여러 개 있습니다.SimpleInjector로 특정 네임 스페이스의 인스턴스를 가져 오는 방법은 무엇입니까?

Context1Namesapce 
    Handler1.cs 
    Handler2.cs 
    Handler3.cs 
Context2Namesapce 
    Handler1.cs 
    Handler2.cs 
CompositeMessageHandler.cs 

나는 CompositeMessageHandler 만 Context1Namespace에서 핸들러를 포함 반환해야합니다 코드 아래, 예를 예를 들어

을 해석 할 때 특정 네임 스페이스에 속한 핸들러가 필요합니다.

Type handlerType = typeof(IMessageHandler<>).MakeGenericType(message.GetType()); 
dynamic handler = _container.GetInstance(handlerType,"Context1Namespace"); 

어떻게하면이 논리를 simpleinjector로 구현할 수 있습니까?

대체 솔루션 : GetInsance 호출 후에 해결 된 인스턴스를 필터링 할 수 있지만 CompositeMessageHandler의 맨 위에 여러 데코레이터 처리기가 있으므로이 솔루션을 사용하면 문제가 발생할 수 있습니다.

+0

왜 네임 스페이스 기반으로 필터링 하시겠습니까? – Steven

+0

각 네임 스페이스마다 다른 작업자 (스레드)가 있습니다. 작업자는 대기열에서 메시지를 가져와 처리기를 실행하므로 각 작업자는 자체 처리기 만 실행해야합니다. – oguzh4n

+0

그런 경우 나는 여전히 네임 스페이스 요구 사항이 이상하다고 생각합니다. 각 핸들러는 일반적으로 자율적이어야하며 자체 큐를 가지고 있으므로 다른 모든 핸들러와 독립적으로 실패하고 재 시도 될 수 있습니다. 네임 스페이스는 중요하지 않습니다. – Steven

답변

0

시나리오에서 두 가지 해결책을 생각해 볼 수 있습니다. 수동으로 InstanceProducer 인스턴스를 만들고이를 처리하여 적절한 핸들러를 실행하거나 일부 주변 값을 사용하고 그러한 핸들러를 실행할 지 여부를 결정하는 데코레이터를 적용하십시오.

수동으로 작성 InstanceProducers :

: 여기

우리가 CompositeMessageHandler<T> 평소와 같이 사용할 수 있습니다 :

// During registration 
var handlerProducerInfos = (
    from type in container.GetTypesToRegister(typeof(IMessageHandler<>), assemblies) 
    let registration = Lifestyle.Transient.CreateRegistration(type, container) 
    from service in type.GetClosedInterfacesFor(typeof(IMessageHandler<>)) 
    let producer = new InstanceProducer(service, registration) 
    select new 
    { 
     Producer = new InstanceProducer(service, registration), 
     Namespace = type.Namespace 
    }) 
    .ToArray(); 

// During execution 
Type handlerType = typeof(IMessageHandler<>).MakeGenericType(message.GetType()); 

var handlers = 
    from info in handlerProducerInfos 
    where handlerType == info.Producer.ServiceType 
    where info.Namespace == "Context1Namespace" 
    select info.Producer.GetInstance(); 

foreach (dynamic handler in handlers) { 

} 

주변 값과 특별한 장식을 사용하여 여기에 모두의 예

public class CompositeMessageHandler<T> : IMessageHandler<T> { private readonly IEnumerable<IMessageHandler<T>> handlers; public CompositeMessageHandler(IEnumerable<IMessageHandler<T>> handlers) { this.handlers = handlers; } public void Handle(T message) { foreach (var handler in this.handlers) { handler.Handle(message); } } } 

그리고 우리는 특별한 장식자를 가지고 있습니다. t는 Simple Injector의 DecoratorContext 개체에 종속됩니다. 간단한 인젝터는 장식에이 클래스를 주입 할 수 있으며, 그것은 당신의 장식 그것을가 실행되는 환경에 대한 자세한 정보를 제공합니다

// Register the concrete message handlers as collection 
container.RegisterCollection(typeof(IMessageHandler<>), assemblies); 

// Register the composite to wrap the real message handlers 
container.Register(typeof(IMessageHandler<>), typeof(CompositeMessageHandler<>)); 

// Register your decorators here: 

// Register our 'contextual' decorator last, but prevent it to be wrapped 
// around the CompositeMessageHandler. 
container.RegisterDecorator(typeof(IMessageHandler<>), 
    typeof(ContextualMessageHandlerDecorator<>), 
    c => !c.ImplementationType.Name.StartsWith("CompositeMessageHandler")); 

실행하는 동안 : 다음과 같이

public class ContextualMessageHandlerDecorator<T> : IMessageHandler<T> { 
    private readonly DecoratorContext context; 
    private readonly IMessageHandler<T> decoratee; 

    public ContextualMessageHandlerDecorator(DecoratorContext context, 
     IMessageHandler<T> decoratee) { 
     this.context = context; 
     this.decoratee = decoratee; 
    } 

    public static string ContextNamespace { get; set; } 

    public void Handle(T message) { 
     // Here we get the ambient value from the ContextHelper and match it 
     // with the namespace of the real message handler 
     if (ContextHelper.ContextNamespace.Value.Equals(
      this.context.ImplementationType.Namespace)) { 
      this.decoratee.Handle(message); 
     } 
    } 
} 

public static ContextHelper { 
    public static readonly ThreadLocal<string> ContextNamespace =new ThreadLocal<string>(); 
} 

우리는 모든 것을 등록 할 수 있습니다

Type handlerType = typeof(IMessageHandler<>).MakeGenericType(message.GetType()); 
// Resolves the composite handler, wrapping all handlers for T. 
dynamic handler = _container.GetInstance(handlerType); 
// Set the context to allow filtering on namespace 
ContextHelper.ContextNamespace.Value = "Context1Namespace"; 
// handle the message 
handler.Handle((dynamic)message); 
+0

"ambient value와 특별한 데코레이터를 사용하는 방법 2"를 구현합니다. 정확히 예상했던 것입니다. 덕분입니다. – oguzh4n

관련 문제