2014-12-16 2 views
1

중첩 된 객체 중 일부가 매개 변수를 전달해야하는 객체 그래프를 해결하기 위해 Autofac 대리 팩토리를 사용하고 싶습니다. 예 : Autofac delegate factory example의 QuoteService에서 데이터를 검색 할 URL이 필요하거나 QuoteService 자체에 매개 변수가 필요한 종속성이있는 경우Autofac 대리인 팩토리가 매개 변수를 중첩 된 객체에 전달할 수 있습니까?

public class WebQuoteService : IQuoteService 
{ 
    public WebQuoteService(Uri source) 
    { 
    } 
} 

public class Shareholding 
{ 
    public Shareholding(string symbol, uint holding, IQuoteService quoteService) 
    { 
    } 
} 

그래서 같이 대리자를 선언하고 등록 할 수 있도록하고 싶습니다 :

public delegate Owned<Shareholding> ShareholdingFactory(string symbol, uint holding, 
                 Uri source); 
builder.RegisterGeneratedFactory<ShareholdingFactory>(); 

내가으로 실행하는 문제는 Autofac가 WebQuoteService의 URI 매개 변수를 해결할 수 있다는 것입니다.

몇 가지 유사한 질문이 있지만 & 해결책을 보았습니다. Autofac-passing-parameter-to-nested-types은 명시 적으로 팩토리를 구현하고 중첩 된 종속성을 해결하기 위해 람다를 등록 할 것을 제안합니다. 그게 효과가있을 것이라고 확신하지만, 매개 변수가 더 깊은 수준에서 필요하거나 더 많은 의존성이 필요한 경우 매우 혼란스러워집니다.

임시 해결책은 Shareholding OnPreparing의 IQuoteService를 해결하고 Autofac 생성 팩토리에서 생성 한 매개 변수를 전달하는 것입니다.

builder.RegisterType<Shareholding>().OnPreparing(e => 
      { 
       e.Parameters = e.Parameters.Union(new[] 
       { 
        new TypedParameter(typeof (IQuoteService), e.Context.Resolve<IQuoteService>(e.Parameters)) 
       }); 
      }); 

다른 매개 변수를 수동으로 해결하지 않아도 괜찮습니다. 실제로 매개 변수를 두 번째 중첩 수준으로 전달하려면 두 번 수행해야합니다.

can-components-be-temporarily-registered-in-an-autofac-container에 의해 제안 된대로 BeginLifetimeScope(Action<ContainerBuilder>)을 사용하려고 시도했지만 사용하지 않으려 고 시도했습니다. 수동으로 팩토리를 구현해야한다고 생각하지만, 모든 중첩 수준에서 작동하도록 URI를 등록 할 수 있습니다.

내가 실제로 할 수 있기를 원하는 것은 WebQuoteService OnPreparing에 첨부하여 델리게이트 팩토리의 매개 변수에 액세스하는 것입니다. 이 같은 것을 리플렉션을 통해 작동하도록 만들 수는 있지만 이상적이지는 않습니다.

builder.RegisterType<WebQuoteService>().OnPreparing(e => 
{ 
    var parameters = e.Context._context._activationStack.Last().Parameters; 
    e.Parameters = e.Parameters.Concat(parameters); 
}); 

누구나 2 단계 깊이 중첩 된 개체에 매개 변수를 전달하는 더 깨끗한 대안을 제안 할 수 있습니까?

+0

*이 질문과 정확히 같지는 않지만 매우 근접합니다. http : // stackoverflow.com/questions/26327177/autofac-resolving-dependencies-with-parameters –

+0

비슷하지만 위임자의 사용이 잘못된 디자인에 대한 의견을 무효화한다고 생각합니다. 위임을 인터페이스로 생각하여 하위 시스템을 만듭니다. 해당 하위 시스템에는 URL이 필요하지만 트리 상단의 개체 (예 : ShareHolding)는 그렇지 않습니다. 팩토리 객체를 만들고 매개 변수가 필요한 구성 요소를 명시 적으로 해결할 수 있었지만 Autofac이 너무 가까울 때 수치스럽게 보입니다. –

답변

2

죄송합니다.하지만 더 나은 제안을 얻지 못하면 최선의 해결책을 문서화해야한다고 생각합니다.

OnPreparing에서 리플렉션을 사용하여 Autofac 활성화 스택 및 대리인 팩토리에 전달 된 매개 변수에 액세스 할 수 있습니다. 그런 다음 분석중인 중첩 된 구성 요소의 매개 변수에 추가 할 수 있습니다. 이 중첩의 모든 수준에서 작동 (만 매개 변수를 필요로하는 구성 요소에 대한 OnPreparing에 추가해야합니다.)

등록과 같이 :

public static class AutofacExtensions 
{ 
    private static readonly FieldInfo ContextFieldInfo; 
    private static readonly FieldInfo ActivationStackFieldInfo; 

    static AutofacExtensions() 
    { 
     var autofacAssembly = typeof(IInstanceLookup).Assembly; 
     Type instanceLookupType = autofacAssembly.GetType("Autofac.Core.Resolving.InstanceLookup"); 
     ContextFieldInfo = instanceLookupType.GetField("_context", BindingFlags.Instance | BindingFlags.NonPublic); 
     Type resolveOperationType = autofacAssembly.GetType("Autofac.Core.Resolving.ResolveOperation"); 
     ActivationStackFieldInfo = resolveOperationType.GetField("_activationStack", BindingFlags.Instance | BindingFlags.NonPublic); 
    } 

    public static IResolveOperation Context(this IInstanceLookup instanceLookup) 
    { 
     return (IResolveOperation)ContextFieldInfo.GetValue(instanceLookup); 
    } 

    public static IEnumerable<IInstanceLookup> ActivationStack(this IResolveOperation resolveOperation) 
    { 
     return (IEnumerable<IInstanceLookup>)ActivationStackFieldInfo.GetValue(resolveOperation); 
    } 

    /// <summary> 
    /// Pass parameters from the top level resolve operation (typically a delegate factory call) 
    /// to a nested component activation. 
    /// </summary> 
    public static void ForwardFactoryParameters(PreparingEventArgs e) 
    { 
     var delegateFactoryActivation = ((IInstanceLookup) e.Context).Context().ActivationStack().Last(); 
     e.Parameters = e.Parameters.Concat(delegateFactoryActivation.Parameters); 
    } 
} 
0
:

builder.RegisterType<WebQuoteService>() 
     .OnPreparing(AutofacExtensions.ForwardFactoryParameters); 

이 헬퍼 클래스를 사용하여

안녕하세요, 저는 here과 비슷한 게시물에 답했습니다. 나는 그것이 분명히 당신을 위해 일할 것이고 그것은 위의 당신의 해결 방법보다 조금 깨끗하다고 ​​생각합니다.

+0

링크 된 질문 및 답변은 ​​공장을 해결하는 방법에 초점을 맞춘 것처럼 보입니다. 공장 사용법은 이미 제안한대로 ('MyApp {public MyApp (ShareHoldingFactory shareHoldingFactory) {...}}')하지만이 질문은 구체적으로 공장을 구현하기 위해 무언가를 등록하는 방법에 관한 것입니다. –