2011-10-04 3 views
1

그래서 다른 사람이 이미 만났던 문제를 해결하려고합니다. 기본적으로, IoC 컨테이너에 대한 호출이 종속성을 재귀 적으로 해결하지만 일부 사용자 정의 코드를 실행하여 미리 정의 된 조건 세트를 기반으로 결과를 변경할 수도 있습니다. Unity IOC 재귀 - 요격기 사용?

내가 컨트롤러과 같이이 말 : 그 모호한, 그래서 제가 예를 들어주게

public class SampleController : Controller 
{ 
     protected SampleType _sampleType = null; 

     public SampleController(SampleType sampleType) 
     { 
      _sampleType = sampleType; 
     } 
} 

나는 또한 (이 컨트롤러의 몇 가지 테스트 버전을 가지고 말하자면 나는 그것을 리팩토링을 내가 만들고 싶어 내가 컨트롤러를 만들 때 유니티를 사용하도록 DefaultControllerFactory을 확장 한

public class SampleController_V2 : SampleController 
{ 
     protected SampleType _sampleType = null; 
     protected AnotherType _anotherType = null; 

     public SampleController_V2(SampleType sampleType, AnotherType anotherType) 
     { 
      _sampleType = sampleType; 
      _anotherType = anotherType; 
     } 
} 

: 그것의 노출을) 테스트 AB에 의해 자극에 끔찍하게 휴식 나던 확인합니다. 이것은 모두 정상적으로 작동합니다. 자, 내가하고 싶은 일은 AB가 해결해야 할 일이 있으면 계층 구조의 특정 유형을 테스트 할 수있는 능력을 제공합니다. 최상위 레벨에서는 잘되지만, 오브젝트 그래프를 통해 반복 될 때 하위 요소에는 적합하지 않습니다.

지금 당장은 적절한 컨트롤러를 선택하여 해결하고 종속성을 부여합니다. 그러나, 나는 AB 테스트에 종속성에 대한 개별 호출을 가로 채지 못하는 것 같습니다. 데이터베이스 구성을 통해 테스트를 정의한 다음 IOC 컨테이너에 기준에 따라 테스트하도록 할 수 있습니다. 예 :

SessionIds that start with the letter 'a': SampleController_V2 
Everyone Else       : SampleController 
UserIds ending in 9      : SampleType_V2 
Everyone Else       : SampleType 

이것은 모두 최상위 항목에 적용됩니다. 그러나 _unityContainer.Resolve(type)에 대한 호출은 재귀 호출 인 것 같지 않습니다.

-> Attempt to Resolve SampleController 
    -> Test Code Tells Us to use _V2 if possible. 
    -> Attempt to Resolve SampleType 
     -> Test Code tells us to use the _V1 if possible. 
    -> Resolves SampleType_V1 
    -> Attempt to Resolve AnotherType 
     -> No Test Defined, Use the Default 
    -> Resolves AnotherType 
-> Resolves SampleController_V2 (passing SampleType_V1 as the dependency and then AnotherType as the other dependency) 

일부 온라인 기사를 통해 찾고 내가 유니티 인터셉터의 어떤 종류를 사용해야처럼 소리,하지만 : 그것은 종류를 해결하려고 할 때 나는 어떤 점에 그 코드를 삽입 할 수 있도록하고 싶습니다 거의 내가이 시점에서 내 자신의 IoC 컨테이너를 작성하고있다. 어떤 종류의 테스트 아키텍처가 내장되어있다.

나는 생성자를 찾은 다음 해결하기 전에이 작업을 수행하는 방법에 대해 좋은 생각을 갖고 있기를 바란다. 각 유형은 재귀 적으로.

EDIT : 실제로 각 종속성의 생성자 매개 변수를 재귀 적으로 검사하여 자체 주입을 만드는 것은 끔찍한 일이지만, 내 자신을 위해 Unity를 버리면 보스 사람들이 약간 혼란 스러울 수도 있습니다. 맞춤 솔루션.

+0

오해의 소지가 있습니다. 입력되는 테스트 데이터에 따라 다른 객체 그래프를 해결하고 싶습니까? 왜 당신이 이것을하고 싶은지 확신 할 수 없습니다. 컨테이너로 테스트 할 때 가능한 한 프로덕션에 가까운 객체 그래프를 유지하려고 노력합니다. –

+0

특정 개체에 대해 AB 테스트를 제공합니다. 예 : EmailSender 클래스가 있다고 가정 해보십시오. 그것은 X입니다. 그러나 다시 작성된 EmailSender 클래스를 테스트하고 싶습니다. 나는 IOC 컨테이너가 Y를 할 장소에 상황 집합에서 EmailSender_V2 클래스를 해결하도록한다. 성능 집중적 일 수 있다고 말한다. 사이트에 부정적인 영향을 줄 수 있는지 천천히 소개하고 싶습니다. 그런 다음 컨트롤 버전을 수정하지 않고도이 코드를 100 %로 기본 버전으로 이동할 수 있습니다. 대부분의 사용자는 동일한 경험을 얻습니다. 일부 사용자는 테스트하는 동안 향상된 경험을 얻습니다. – Tejs

답변

0

나는 내 맞춤 솔루션을 만드는 길로 가려고한다고 생각합니다. 사실, 나는 현재의 IoC를 해킹해야만했다. 내가 원하는 효과를 얻기 위해 사용하고 있는데, 이는 내 솔루션을 만드는 것보다 훨씬 낫다.나는 심지어 의존성의 간단한 해결책 이외의 대부분의 기능에 대해 IoC를 사용하지 않고있어, 그것을 사용하지 않을 것이라는 확신이 없다. 나는 다음과 같은 방법으로 끝냈다.

public virtual object Resolve(Type requestedType, Session session = null, RequestContext requestContext = null) 
{ 
    ConstructorInfo constructor = requestedType.GetConstructors().First(); 
    object[] dependencies = null; 
    Type resultType = requestedType; 

    if (session == null || requestContext == null) 
    { 
     dependencies = constructor.GetParameters().Select(parameter => Resolve(parameter.ParameterType)).ToArray(); 
    } 
    else 
    { 
     InitializeTestingArchitecture(); 

     var testVersion = _testingProvider.GetTestVersionFor(requestedType, requestContext, session); 

     if(testVersion == null) 
      return Resolve(requestedType); 

     resultType = _testTypeLoader.LoadTypeForTestVersion(requestedType, testVersion); 
     constructor = resultType.GetConstructors().First(); 

     dependencies = constructor.GetParameters().Select(parameter => Resolve(parameter.ParameterType, session, requestContext)).ToArray(); 
    } 

    return Activator.CreateInstance(resultType, dependencies); 
} 

이렇게하면 데이터베이스 레코드를 통해 AB 클래스 인스턴스의 노출을 제어 할 수있다.

1

요청 기간 동안 Unity 컨테이너를 스왑하려고합니다. 그것이 당신의 "V2"조건이고 새로운 컨테이너를 만들지 만 등록 된 다른 종류의 세트를 가지고 있는지 확인하십시오. 해당 요청의 범위 내에서 사용하십시오. 프로덕션에서 요청할 때마다 새 컨테이너를 만드는 것은 좋은 생각이 아니지만 테스트를 위해 좋은 아이디어 여야합니다.

+0

그러면 특정 요청에 대해 'Register ()'를 수행하는 임시 컨테이너를 만들겠습니까? – Tejs

+0

네, 맞습니다. – RandomEngy

+0

유일한 문제는 잠재적으로 모든 요청에 ​​임시 단위 컨테이너가 있다는 것입니다. 그렇게 비싸지 않아? – Tejs

1
당신이 Create 방법과 ABEmailSenderFactory을 작성할 수 있습니다 가정

... Autofac에서

그것이 내가 유니티에 대해 잘 모르는 쉽게

builder.RegisterType<ABEmailSenderFactory>().AsSelf(); 

builder.Register(c => c.Resolve<ABEmailSenderFactory>().Create()) 
    .As<EmailSender>(); 

로 것이지만, it looks like it may not be as easy.

0

여기에서 사용할 수있는 몇 가지 옵션이 있습니다. Unity 2.0을 여기 있다고 가정합니다. 이전 버전에서는 더 어려웠습니다.

당신은 미리의 다양한 순열을 계산할 사전과 해결 통화에서 해결 재 지정을 사용할 수 있습니다 : 그것은이가 트리에 나타납니다 곳 SampleType에 대한 해결 된 오브젝트를 대체 할

container.Resolve(figureOutControllerType(), 
    new DependencyOverride<SampleType>(figureOutSampleType())); 

하지만 필요합니까 인스턴스를 직접.

A/B 테스트 대상 요소의 조합마다 이름이 지정된 등록을 사용하고 NxM 등록 집합을 사용할 수 있습니다. 그것은 약 4 변경 후 정말 지저분 해 지지만.

container.RegisterType<SimpleType>(
    new InjectionFactory((c) => container.Resolve(figureOutWhichType())); 

이것은 figureOutWhichType 방법이하는 무엇을 기반으로 런타임 스위치를 할 것입니다 : 공장 출하시 사용하는 일을 알아낼 수 -

당신은 당신에 대해 테스트하는 것들에 대한 injectionfactory를 사용할 수 있습니다.

세 번째 옵션은 유형 연결 매핑 전략을 추가하여 해결 체인 내부의 논리를 처리하는 컨테이너 확장입니다.

이 옵션 중 공장 출하 방식부터 시작하여 상황이 나빠질 경우 사용자 지정 확장 프로그램으로 이동할 수 있습니다.