2012-11-16 3 views
3

데이터베이스 연결 수명주기를 처리하기위한 간단한 인터셉터 (Castle.DynamicProxy 포함)를 작성했습니다. 나는. 모든 서비스에는 처음 사용할 때 새로운 서비스를 여는 Connection 속성이 있습니다. 연결은 각 메서드 호출 후 자동으로 종료되고 : https://gist.github.com/4087483IEnumerable을 반환하는 메서드에 대한 인터셉터를 작성하는 방법

가있는 경우 "사용 (새 :

[Test] 
public void ConnectionClosedByProxy() 
{ 
    // arrange 
    var service = new MyService(); 
    var proxy = new ProxyGenerator() 
     .CreateInterfaceProxyWithTarget<IMyService>(
      service, new CloseConnectionInterceptor()); 

    // act 
    proxy.GetList(); 

    // assert: works!!! 
    Assert.IsFalse(service.IsConnectionOpen); 
} 

[Test] 
public void IteratorLeavesOpenConnection() 
{ 
    // arrange 
    var service = new MyService(); 
    var proxy = new ProxyGenerator() 
     .CreateInterfaceProxyWithTarget<IMyService>(
      service, new CloseConnectionInterceptor()); 

    // act 
    proxy.GetEnumerable().ToList(); 

    // assert: bad, bad, bad! 
    Assert.IsTrue(service.IsConnectionOpen); 
} 

여기에 전체 예를 참조하십시오

class CloseConnectionInterceptor : IInterceptor 
{ 
    public void Intercept(IInvocation invocation) 
    { 
     try 
     { 
      invocation.Proceed(); 
     } 
     finally 
     { 
      var hasConnection = invocation.InvocationTarget as IHasConnection; 
      if (hasConnection.IsConnectionOpen) 
      { 
       hasConnection.Connection.Dispose(); 
       hasConnection.Connection = null; 
      } 
     } 
    } 
} 

interface IHasConnection 
{ 
    bool IsConnectionOpen { get; } 
    Connection Connection { get; set; } 
} 

이 반복자를 반환하는 방법을 제외하고 잘 작동합니다 연결 반복자에 마지막으로 액세스 한 후 폐쇄되고 - 예상은 나의 GetEnumerable 방법 내부 연결()) "문은 다음 작동합니다. 요격기에서이 순간을 잡을 수 있습니까? 아니면 메서드뿐만 아니라 결과 IEnumerable 프록시해야합니까?

답변

0

는 내 질문에 대답의 씨앗을 넣어 :). 여기에도를 IEnumerable을 발생하는 프록시 수정 인터셉터는 다음과 같습니다

class CloseConnectionInterceptor : IInterceptor 
{ 
    public void Intercept(IInvocation invocation) 
    { 
     Type genericType = invocation.Method.ReturnType.IsGenericType 
      ? invocation.Method.ReturnType.GetGenericTypeDefinition() 
      : null; 

     if (genericType == typeof(IEnumerable<>)) 
     { 
      invocation.Proceed(); 

      var method = GetType() 
       .GetMethod("HandleIteratorInvocation") 
       .MakeGenericMethod(
        invocation.Method.ReturnType.GetGenericArguments()[0]); 

      invocation.ReturnValue = method.Invoke(
       null, 
       new[] { invocation.InvocationTarget, invocation.ReturnValue }); 
     } 
     else 
     { 
      HandleNonIteratorInvocation(invocation); 
     } 
    } 

    public static IEnumerable<T> HandleIteratorInvocation<T>(
     IHasConnection hasConnection, IEnumerable enumerable) 
    { 
     try 
     { 
      foreach (var element in enumerable) 
       yield return (T)element; 
     } 
     finally 
     { 
      CloseOpenConnection(hasConnection); 
     } 
    } 

    private static void HandleNonIteratorInvocation(IInvocation invocation) 
    { 
     try 
     { 
      invocation.Proceed(); 
     } 
     finally 
     { 
      CloseOpenConnection(invocation.InvocationTarget as IHasConnection); 
     } 
    } 

    private static void CloseOpenConnection(IHasConnection hasConnection) 
    { 
     if (hasConnection.IsConnectionOpen) 
     { 
      hasConnection.Connection.Dispose(); 
      hasConnection.Connection = null; 
     } 
    } 
} 
+0

모두/일반 제네릭이 아닌 IEnumerable을 지원하는 마지막 버전 : https://gist.github.com/4109938 – orientman

관련 문제