2012-02-24 4 views
4

저는 최근에 Ninject, Castle Windsor 및 다른 IoC 컨테이너를 사용한 후 새로운 ASP.NET MVC 프로젝트에서 Autofac을 시험 중입니다. 따라서 일반적으로 IoC 컨테이너에 대해 알고 있지만, 필자는 Autofac을 처음 접했고 아직도 모범 사례를 찾고 있습니다.Autofac : 가장 안쪽의 범위를 해결하는 방법은 무엇입니까?

현재 가장 안쪽으로 중첩 된 범위를 해결할 수있는 방법이 있는지 알아 내려고하고 있습니다.

다음과 같은 상황이 있습니다. SingleInstance()로 등록 된 구성 요소는 중첩 된 수명 범위를 만들고, 일부 구성 요소를 InstancePerLifetimeScope로 구성하는 구성 작업을 제공하며,이 중첩 된 범위 내에서 등록 된 구성 요소를 과 같이, 유용한 무언가를 :

ILifetimeScope currentScope = ???; 

using (var scope = currentScope.BeginLifetimeScope(cb => { 
    cb.RegisterType<X>().InstancePerLifetimeScope(); 
    // ... 
})) 
{ 
    var comp = scope.Resolve<X>(); 
    // ... 
} 

문제는 내가 X는 가장 안쪽의 범위를 내부 구성 요소에 의존한다는 것을 알고 있기 때문에 내가 currentScope 가장 안쪽 평생 범위 싶습니다 것입니다. 가장 단순한 경우에는 예를 들어 현재 요청 수명 범위. 물론 AutofacDependencyResolver.Current.RequestLifetimeScope를 사용하여 얻을 수는 있지만 실제로 테스트 할 수는 없으므로 사용하지 않으려합니다. 또한 평생 범위가 반드시 가장 내면의 범위는 아닙니다.

그래서, 예를 들어 주어진 최장 수명 범위를 찾는 방법이 있습니까? 루트 컨테이너 또는 다른 ILifetimeScope?

답변

4

Autofac에서 가장 안쪽의 범위는 항상 컨테이너입니다. AutofacDependencyResolver를 사용하면, (당신이 가진 모든이 ILifetimeScope 경우) 용기에 도착 "뒤로 걷기"를 AutofacDependencyResolver.Current.ApplicationContainer

중첩 된 범위에서 방법이 없습니다 것. 어쨌든 그렇게하고 싶지는 않습니다.

기본적으로 SingleInstance 구성 요소는 특정 구성 요소의 수동 등록/해결을 통해 일종의 서비스 위치를 수행하는 것처럼 들립니다. 등록 된 유형 집합이 고정되어 있으면 가능한 경우 시스템의 일부 재 설계를 권장 할 수 있으므로 SingleInstance 구성 요소가 더 이상 SingleInstance로 등록되지 않고 대신 InstancePerDependency로 등록 된 다음 해당 항목을로 가져옵니다. 생성자 매개 변수. 대신

...

// Consuming class like this... 
public class BigComponent 
{ 
    public void DoSomethingCool() 
    { 
    using(var scope = ...) 
    { 
     var c = scope.Resolve<SubComponent>(); 
     c.DoWork(); 
    } 
    } 
} 

// ...and container registrations like this... 
builder.RegisterType<BigComponent>().SingleInstance(); 

당신은 조금 반전 시도 할 수 있습니다 :

// Consuming class like this... 
public class BigComponent 
{ 
    private SubComponent _c; 
    public BigComponent(SubComponent c) 
    { 
    _c = c; 
    } 
    public void DoSomethingCool() 
    { 
    _c.DoWork(); 
    } 
} 

// ...and container registrations like this... 
builder.RegisterType<BigComponent>().InstancePerDependency(); 
builder.RegisterType<SubComponent>().InstancePerLifetimeScope(); 

아이디어는 온 - 더 - 플라이 등록 및 즉각적인 할 필요가 없습니다 것입니다 - 해상도 문제. 당신이 서비스 위치를하고 붙어 있다면 당신이 그렇게하면

, 당신은 분해되지 않습니다 당신이 InstancePerHttpRequest에 범위 레지스터 물건을 당신은 절대 안쪽의 범위를 필요로하는 경우 AutofacDependencyResolver.Current.ApplicationContainer를 사용하지만, 명심해야 당신이 그렇게 문제가 생길 수 있습니다. 대신 AutofacDependencyResolver.Current.RequestLifetimeScope을 사용하는 것이 좋습니다. 테스트 환경에서

var requestScope = AutofacDependencyResolver.Current.RequestLifetimeScope; 
using (var scope = requestScope.BeginLifetimeScope(cb => { 
    cb.RegisterType<X>().InstancePerLifetimeScope(); 
    // ... 
})) 
{ 
    var comp = scope.Resolve<X>(); 
    // ... 
} 

AutofacDependencyResolver 당신이 요청 수명이 생성되는 방법을 규정하는 업체에서 교환 할 수 있습니다 : 그것은 당신의 방법을 만들 것입니다.다시

public class TestLifetimeScopeProvider : ILifetimeScopeProvider 
{ 
    readonly ILifetimeScope _container; 
    private ILifetimeScope _lifetimeScope = null; 

    public TestLifetimeScopeProvider(ILifetimeScope container) 
    { 
     if (container == null) throw new ArgumentNullException("container"); 
     _container = container; 
    } 

    public ILifetimeScope ApplicationContainer 
    { 
     get { return _container; } 
    } 

    public ILifetimeScope GetLifetimeScope() 
    { 
     if (_lifetimeScope == null) 
     { 
      _lifetimeScope = ApplicationContainer.BeginLifetimeScope("httpRequest") 
     } 
     return _lifetimeScope; 
    } 

    public void EndLifetimeScope() 
    { 
     if (_lifetimeScope != null) 
      _lifetimeScope.Dispose(); 
    } 
} 

, 단위 테스트를위한 단지 스텁, 당신이 이제까지 생산에 사용하는 거라고하지 뭔가 :이 같은 간단한/스텁 하나를 구현할 수 있습니다.

var lsProvider = new TestLifetimeScopeProvider(container); 
var resolver = new AutofacDependencyResolver(container, lsProvider); 
DependencyResolver.SetResolver(resolver); 

이것은 실제로 진짜 요청 컨텍스트를하지 않고 단위 테스트 내부 InstancePerHttpRequest 등을 사용할 수 있습니다 : 당신이 당신의 시험에서 DependencyResolver을 연결할 때

그런 다음, 당신은 당신의 평생 범위 제공자를 제공합니다. 또한 등록/해결 방법에서 요청 평생 범위를 사용할 수 있어야하며 응용 프로그램 컨테이너로 되돌릴 필요가 없음을 의미합니다.

+0

필자의 경우 "BigComponent"는 응용 프로그램의 전체 수명 동안 특정 개체를 보유하는 레지스트리입니다. 중첩 된 범위는 응용 프로그램 시작 (첫 번째 HTTP 요청) 중에 동적으로 발견 된 일부 유형 (플러그인 아키텍처)을 인스턴스화하는 데 사용됩니다. 내 현재 솔루션은'() => AutofacDependencyResolver.Current.RequestLifetimeScope'로 등록 된 "BigComponent"에 Func 를 삽입하는 것입니다. 아직 좋지는 않지만 범위를 벗어난 서비스 위치 지정자에 대한 정적 참조를 남겨 둡니다. [계속] –

+0

BTW : 가장 안쪽 범위가 가장 깊게 중첩 된 범위를 의미했습니다. 나를 위해, 응용 프로그램 컨테이너가 가장 _ 범위입니다. –

+0

내면/외면에 대한 오해. 죄송합니다. 어느 쪽이든, 어느 방향 으로든 스택을 걸을 수는 없으므로 서비스 위치를 수행해야하는 경우 AutofacDependencyResolver가 필요합니다. MVC IDependencyResolver를 사용하면 DependencyResolver.Current.GetService는 항상 요청 수명에서 벗어날 것이므로 람다가 필요하지 않을 수도 있습니다. 그래서, 그래, 당신은 여전히 ​​그것을 필요합니다. –

관련 문제