2011-10-24 1 views
3

asp.net에서 Autofac 2.5를 사용하고 있으며 수명 인스턴스 구성 요소가 단일 인스턴스 구성 요소의 종속성으로 해결되어 내 스레드 안전을 손상시키는 문제가 있습니다. 이것은 등록 문제이지만 Autofac이이를 위반으로보고 예외를 던질 것으로 생각했습니다.Autofac은 혼합 된 범위를 가진 구성 요소를 해결합니다.

private class A{} 

    private class B 
    { 
     public B(A a){} 
    } 

    [Test] 
    [ExpectedException()] 
    public void SingleInstanceCannotResolveLifetimeDependency() 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterType<A>() 
      .InstancePerLifetimeScope(); 
     builder.RegisterType<B>() 
      .SingleInstance(); 

     using (var container = builder.Build()) 
     { 
      using (var lifetime = container.BeginLifetimeScope()) 
      { 
       //should throw an exception 
       //because B is scoped singleton but A is only scoped for the lifetime 
       var b = lifetime.Resolve<B>(); 
      } 
     } 
    } 

이런 경우에는 Autofac에서 종속성 해결 예외를 발생시키는 방법이 있습니까? SingleInstance이 범위 단지 루트 수명입니다 - - 그것은 웹 환경에서 잠재적으로 위험 할 수 있습니다이 Autofac에 대한 올바른 동작이 비록

UPDATE . 모든 개발자가 올바른 등록을 받도록하는 것이 고통 스러울 수 있습니다. 다음은 수명 범위 영역 인스턴스가 루트 범위에서 확인되지 않도록 인스턴스 조회를 검사하는 Autofac의 작은 확장 방법입니다. 웹 프로젝트에서 생명주기 문제를 제거하는 데 도움이되었다는 것을 알고 있습니다.

public static class NoLifetimeResolutionAtRootScopeExtensions 
{ 
    /// <summary> 
    /// Prevents instances that are lifetime registration from being resolved in the root scope 
    /// </summary> 
    public static void NoLifetimeResolutionAtRootScope(this IContainer container) 
    { 
     LifetimeScopeBeginning(null, new LifetimeScopeBeginningEventArgs(container)); 
    } 

    private static void LifetimeScopeBeginning(object sender, LifetimeScopeBeginningEventArgs e) 
    { 
     e.LifetimeScope.ResolveOperationBeginning += ResolveOperationBeginning; 
     e.LifetimeScope.ChildLifetimeScopeBeginning += LifetimeScopeBeginning; 
    } 

    private static void ResolveOperationBeginning(object sender, ResolveOperationBeginningEventArgs e) 
    { 
     e.ResolveOperation.InstanceLookupBeginning += InstanceLookupBeginning; 
    } 

    private static void InstanceLookupBeginning(object sender, InstanceLookupBeginningEventArgs e) 
    { 
     var registration = e.InstanceLookup.ComponentRegistration; 
     var activationScope = e.InstanceLookup.ActivationScope; 

     if (registration.Ownership != InstanceOwnership.ExternallyOwned 
      && registration.Sharing == InstanceSharing.Shared 
      && !(registration.Lifetime is RootScopeLifetime) 
      && activationScope.Tag.Equals("root")) 
     { 
      //would be really nice to be able to get a resolution stack here 
      throw new DependencyResolutionException(string.Format(
       "Cannot resolve a lifetime instance of {0} at the root scope.", registration.Target)) 
     } 
    } 
} 

컨테이너를 만들 때 적용하면 평생 범위 서비스가 루트 범위에서 해결 될 때 예외가 발생합니다.

container.NoLifetimeResolutionAtRootScope(); 

답변

3

예 - 당신은 자식 범위의 이름을 명시 적으로 함께 구성 요소 A 연결해야합니다. 그렇지 않으면 관찰 할 때 A 인스턴스가 루트 (컨테이너) 범위에 만들어집니다.

// Replace `A` registration with: 
builder.RegisterType<A>().InstancePerMatchingLifetimeScope("child"); 

그리고 ...

// Replace scope creation with: 
using (var lifetime = container.BeginLifetimeScope("child")) { 
+0

감사합니다, 그것은 하나의 인스턴스가 단지 루트 수명이 범위 것을 알아낼 걸 렸어요. – Danielg

+0

작은 확장 메서드를 사용하여 내 질문을 업데이트하여 이러한 예외를 throw합니다. "_activationStack"이 ResolveOperation에 노출되면 더 유용한 정보를 던질 수 있습니다. – Danielg