Skip to content

수행 문맥

Fox Transactions 이 제공하는 다양한 기능들은 트랜잭션 메서드 호출 전/후에 전처리(preprocessing)와 후처리(postprocessing)를 수행함으로써 구현됩니다. 이러한 전처리와 후처리에 필요한 다양한 정보를 수행 문맥(Execution Context)이라 부르며 Fox Transactions 의 가장 중요한 정보를 포함합니다. Fox Transactions 의 선언적 트랜잭션(declarative transaction) 기능과 자동 트랜잭션(automatic transaction) 기능은 모두 수행 문맥에 기록된 FoxTransactionOption 정보, FoxAutoComplete 정보를 사용합니다.

Fox Transactions 작동 원리

Fox Transactions 의 핵심 작동 원리는 메서드 호출 전에 트랜잭션을 시작하는 등의 작업을 수행하는 전처리와 메서스 종료 후 트랜잭션을 커밋하거나 롤백하는 등의 후처리 작업을 수행하는 것입니다. 이 전처리/후처리에 필요한 부분이 수행 프록시(execution proxy)이며 수행 프록시와 전처리/후처리에 필요한 정보들을 담고 있는 것이 수행 문맥 입니다.

호출 프록시와 수행 문맥

수행 프록시/문맥 생성

Fox Transacionts 의 기능을 사용하려면 FoxComponentBase 추상 클래스에서 제공하는 CreateExecution<T> 메서드를 호출하고 이 메서드가 반환하는 인터페이스를 통해 대상 트랜잭션 메서드(이 예제에서는 InsertMany 메서드)를 호출해야 합니다.

1
2
3
BizClass biz = new();
IBizClass itf = biz.CreateExecution<IBizClass>();
itf.InsertMany([997, 998, 999]);

CreateExecution<T> 메서드를 호출하면 Fox Transactions 는 수행 프록시를 생성합니다. 수행 프록시는 호출에 사용하는 인터페이스(이 예제의 경우 IBizClass 인터페이스)를 구현하기 때문에 InsertMany 메서드가 호출되면 실제 메서드가 아닌 호출 프록시가 호출됩니다. 이 때 수행 프록시는 수행 문맥 객체를 생성합니다. 수행 문맥은 FoxExecutionContext 객체로 표현되며 다양한 정보를 포함하고 있습니다. 현재 활성화된 수행 문맥 객체는 Current 정적 속성을 통해 접근할 수 있습니다.

Console.WriteLine($"Is in execution context? {FoxExecutionContext.Current == null ? "No" : "Yes"}");

전처리/후처리

수행 프록시는 수행 문맥을 생성한 이후 실제 메서드 호출 전에 필요한 전처리(preprocessing)를 수행합니다. 전처리에는 트랜잭션 생성하거나 기존 트랜잭션에 참여하거나 FoxDbAccess 객체를 생성하는 등의 작업을 포함합니다. 이러한 전처리가 완료되면 실제 메서드를 호출하게 됩니다.

실제 메서드는 코드를 수행하고 정상적으로 반환하거나 예외를 발생하여 비 정상적인 반환을 수행하며 제어는 Fox Transactions 의 후처리(postprocessing)로 넘어가게 됩니다. Fox Transactions 의 후처리는 예외 발생 여부에 따라 트랜잭션을 커밋하거나 롤백하고 트랜잭션에 사용한 자원들(데이터베이스 연결, FoxDbAccess 객체 등)을 해제하는 작업을 포함합니다. Fox Transactions 의 후처리가 끝나면 수행 프록시를 통해 실제 메서드의 결과값(return value)이 호출자에게 반환되며 생성되었던 수행 문맥은 제거됩니다.

수행 프록시는 객체 단위로 생성 및 해제되지만 수행 문맥은 메서드 호출 단위로 생성 및 해제됨에 주목하십시요. 즉, 수행 프록시를 통해 트랜잭션 메서드가 호출될 때마다 수행 문맥은 매번 다시 생성되며 메서드 호출이 종료되면 수행 문맥은 제거되는 반면 수행 프록시는 여전히 다시 사용할 수 있습니다.

1
2
3
4
5
using BizClass biz = new();
IBizClass itf = biz.CreateExecution<IBizClass>();  // 수행 프록시 생성됨
itf.InsertMany([991, 992, 993]);    // 수행 문맥 #1 생성
itf.InsertMany([994, 995, 996]);    // 수행 문맥 #2 생성
itf.InsertMany([997, 998, 999]);    // 수행 문맥 #3 생성

수행 문맥 객체

수행 문맥은 FoxExecutionContext 클래스로 표현되며 현재 수행문맥에 접근하기 위해서 Current 정적 속성을 제공합니다. 콘솔 프로그램의 Main 메서드나 ASP.NET 코드들과 같은 비 트랜잭션 코드에서 Current 속성에 접근하면 활성화된 수행 문맥이 존재하지 않기 때문에 null 값이 반환됩니다.

하지만 앞서 예제에서 수행 프록시를 통해 호출된 InsertMany 메서드 내부 코드에서는 Current 속성은 현재 활성화된 수행 문맥을 나타내는 FoxExecutionContext 객체를 반환합니다. FoxComponentBase 클래스는 현재 활성화된 수행 문맥을 나타내는 Context 속성을 제공하며, 이 속성값은 메서드 내에서 호출된 FoxExecutionContext.Current 속성값과 동일합니다.

1
2
3
4
5
6
7
8
9
public class BizClass : FoxBizBase, IBizClass
{
    public void InsertMany(int[] ids)
    {
        Debug.Assert(this.Context != null);
        Debug.Assert(this.Context == FoxExecutionContext.Current);
        ......
    }
}

트랜잭션 메서드 내에서 Context 속성이나 FoxExecutionContext.Current 속성이 항상 null 이 아닌 값을 가지지는 않습니다. 만약 트랜잭션 메서드를 수행 프록시를 거치지 않고 직접 호출된 경우 수행 문맥이 생성되지 않기 때문에 Context 속성이나 FoxExecutionContext.Current 속성은 null 값을 반환합니다. 수행 문맥이 존재하지 않으면 전처리와 후처리도 발생하지 않으며 Fox Tranactions 가 제공하는 선언적 자동 트랜잭션 기능은 전혀 작동하지 않습니다. 따라서 다음 예제 코드는 InvalidOperationException 예외를 발생시킵니다.

static void Main()
{
    Debug.Assert(FoxExecutionContext.Current == null);
    using BizClass biz = new();
    biz.InsertMany([991, 992, 993]);
}

public class BizClass : FoxBizBase, IBizClass
{
    public void InsertMany(int[] ids)
    {
        if (this.Context == null)
        {
            Debug.Assert(FoxExecutionContext == null);
            throw new InvalidOperationException("There is no active execution context.");
        }
        ......
    }
}

FoxExecutionContext 클래스

FoxExecutionContext 클래스는 Fox Transactions 가 제공하는 기능을 처리하기 위한 다양한 정보를 포함합니다. 이 클래스는 수행 확장(Execution Extension)에서도 사용 가능하며 다음 정보들을 포함합니다.

호출 정보

FoxExecutionContext 클래스는 호출 대상 트래잭션 메서드에 대한 리플렉션 정보를 제공합니다. 모든 트랜잭션 메서드 호출전에 항상 호출되는 FoxComponentBase.Activate 메서드에서 이 정보를 사용하여 구체적인 호출 대상 메서드가 어떤 메서드인지 구별이 가능합니다.

public class BizClass : FoxBizBase, IBizClass
{
    // 메서드 호출 전에 호출됩니다.
    protected override void Activate()
    {
        FoxExecutionContext ctx = this.Context;
        this.Log.Verbose($"{ctx.MethodName} activated.");
    }

    // 메서드 호출 후에 호출됩니다.
    protected override void Deactivate()
    {
        FoxExecutionContext ctx = this.Context;
        this.Log.Verbose($"{ctx.MethodName} dectivated.");
        if (ctx.Exception != null)
        {
            this.Log.Error(ctx.Exception);
        }
    }

    ...... 생략 ......
}
  • TargetObject 속성

    수행 프록시가 아닌 실제 메서드 호출 대상이되는 객체에 대한 객체 참조 입니다. 위 예제에서는 BizClass 타입 인스턴스에 대한 참조입니다.

  • MethodBase 속성

    호출할 실제 메서드에 대한 리플렉션 정보(System.Reflection.MethodBase 타입) 입니다.

  • MethodCallMessage 속성

    호출에 대한 정보를 담는 IMethodCallMessage 객체 입니다. IMethodCallMessage.Args 속성을 통해 실제 호출에서 사용한 매개변수 값에 접근할 수 있습니다.

  • MethodReturnMessage 속성

    호출 결과에 대한 정보를 담는 IMethodReturnMessage 객체 입니다. IMethodReturnMessage.Result 속성을 통해 메서드가 반환 값에 접근할 수 있습니다.

  • Exception 속성

    호출한 메서드가 예외를 발생한 경우 발생한 예외 객체를 나타냅니다. 이 속성값이 null 이 아닌 경우 호출한 메서드가 예외를 발생한 것입니다.

트랜잭션 정보

트랜잭션 메서드에 대한 트랜잭션 설정 정보와 트랜잭션 사용 여부 정보을 제공합니다.

  • TransactionInfo 속성

    FoxTransactionInfo 객체를 통해 메서드에 설정된 트랜잭션 옵션(FoxTransactionOption), 격리 수준, 타임아웃 등의 트랜잭션 정보를 제공합니다. 이 속성이 제공하는 정보는 클래스 수준 혹은 메서드 수준에 설정된 FoxTransactionAttribute 특성을 모두 고려하여 최종적으로 적용되는 트랜잭션 설정 입니다.

  • IsInTransaction 속성

    수행 문맥이 트랜잭션 내에서 수행되고 있는지 여부를 반환합니다. 이 속성의 반환값은 FoxContextUtil.IsInTransction 속성과 동일한 값입니다.

  • TransactionControllerType 속성

    수행 문맥의 트랜잭션이 사용하는 트랜잭션 컨트롤러의 타입을 반환합니다. 이 속성 값은 FoxTransactionControllerAttribute 특성이 클래스 혹은 메서드 수준에서 설정된 상황과 이 특성에 설정된 FoxTransactionControllerKind 열거 타입이 고려되어 최종적으로 결정된 트랜잭션 컨트롤러의 타입을 나타내며 현재 시작된 트랜잭션이 존재하지 않더라도 이 속성 값은 설정된 트랜잭션 컨트롤러 타입을 반환합니다.

기타 메타 정보

FoxExecutionContext 클래스는 호출 정보 및 트랜잭선 정보 이외에도 다음과 같은 추가적인 메타 정보들을 포함합니다.

  • IsAutoComplete 속성

    수행 문맥에서 호출할 실제 메서드가 자동 트랜잭션을 사용하는지 여부 입니다. 즉, 메서드의 실질 FoxAutoCompleteAttribute 특성 설정값이 true 인지 여부를 반환합니다.

  • IsRootContext 속성

    수행 문맥이 트랜잭션 루트인가 여부를 반환합니다.

  • Data 속성

    수행 확장(execution extension) 기능에서 사용가능한 Dictionary<string, object> 데이터 객체 입니다. 예를 들어, 전처리에서 값을 설정해 두고 후처리에서 이 값을 꺼내어 사용할 수 있습니다.

FoxContextUtil 클래스

FoxContextUtil 클래스는 수행 문맥에 접근할 수 있는 또 다른 정적(static) 헬퍼 클래스 입니다. .net framework 가 COM+ 를 위해 System.EnterpriseServices 네임스페이스에서 제공했던 ContextUtil 클래스와 유사한 기능을 제공합니다. 이 클래스는 다음과 같은 메서드/속성을 제공합니다.

  • IsInContext 속성

    현재 코드가 수행 문맥 하에서 수행되는지 여부를 나타냅니다.

  • SetComplete/SetAbort 메서드

    수동 트랜잭션에서 트랜잭션 투표를 지정하기 위한 메서드 입니다. 트랜잭션 성공을 나타내기 위해서 SetComplete 메서드를, 트랜잭션 실패를 나타내기 위해서 SetAbort 메서드를 사용합니다.

  • EnableCommit/DisableCommit 메서드

    COM+ 호환을 위해 제공되는 메서드로서 SetComplete 메서드와 SetAbort 메서드와 동일한 기능을 수행합니다. COM+ 에서는 EnableXXX 메서드들와 SetXXX 메서드들의 용도가 약간 다르지만 Fox Transations 에서는 두 메서드들의 용도는 완전히 동일합니다.

  • MyTransactionVote 속성

    수동 트랜잭션에서 메서드의 트랜잭션 투표를 나타내는 속성입니다. 이 속성 값이 true 라면 이전에 SetComplete 메서드가 호출된 것이고 false 라면 이전에 SetAbort 메서드가 호출된 것입니다.

  • IsInTransaction 속성

    FoxExecutionContext 클래스의 IsInTransaction 속성과 동일하게 트랜잭션 사용 여부를 나타냅니다.

  • IsAutoComplete 속성

    FoxExecutionContext 클래스의 IsAutoComplete 속성과 동일하게 트랜잭션 메서드가 자동 트랜잭션을 사용하는지를 나타냅니다.

  • 기타 속성들

    ContextId 속성은 현재 수행 문맥이 존재하는 경우, 수행 문맥의 Id 를 반환하며(FoxExecutionContext.Current.Id) 그렇지 않은 경우 0 을 반환합니다.

    그외의 속성들(ApplicationName, DeactivateOnReturn 등)은 COM+ 호환을 위해 제공되었던 속성들로 그 값이 의미가 없거나 사용되지 않습니다.

Warning

IsInContext, ContextId 속성을 제외한 FoxContextUtil 클래스의 대부분의 속성/메서드들은 수행 문맥이 없는 상황, 즉 트랜잭션 메서드가 아닌 상황에서 호출되면 InvalidOperationException 예외를 유발합니다. 따라서 먼저 IsInContext 속성 값이 true 인지 확인하고 다른 메섣/속성에 접근하는 것이 좋습니다.

Summary

Fox Transactions 의 트랜잭션 처리 기능은 수행 프록시에 의해 트랜잭션 메서드 호출이 가로채어져 전처리와 후처리를 통해 작동합니다.

FoxExecutionContext 클래스로 표현되는 수행 문맥 객체는 Fox Transactions 의 핵심 기능인 트랜잭션을 위한 전처리/후처리에 필요한 핵심적인 정보를 포함합니다. 수행 문맥 객체는 Fox Transactions 의 선언적 트랜잭션 처리와 자동 트랜잭션 처리에 사용될 뿐만 아니라 수행 확장(execution extension) 기능을 통해 AOP 구현에도 사용될 수 있습니다.