이 샘플에서는 클라이언트에서 조정하는 트랜잭션의 사용법과 WS-Atomic Transaction 또는 OleTransactions 프로토콜을 사용하는 트랜잭션 흐름의 클라이언트 및 서버 옵션을 보여 줍니다. 이 샘플은 계산기 서비스를 구현하는 Getting Started 샘플을 기반으로 하지만 작업에서는 TransactionFlowOption 열거형과 함께 TransactionFlowAttribute를 사용하여 트랜잭션 흐름을 사용할 수 있는 범위를 결정하는 방법을 보여 줍니다. 흐름이 지정된 트랜잭션의 범위 내에서는 요청한 작업에 대한 로그가 데이터베이스에 기록되고 클라이언트에서 조정하는 트랜잭션이 완료될 때까지 유지됩니다. 클라이언트 트랜잭션이 완료되지 않으면 웹 서비스 트랜잭션에서 데이터베이스에 적합한 업데이트가 커밋되지 않도록 합니다.
참고
이 샘플의 설치 절차 및 빌드 지침은 이 항목의 끝부분에 나와 있습니다.
서비스 및 트랜잭션에 대한 연결을 시작하면 클라이언트에서 여러 가지 서비스 작업에 액세스합니다. 서비스에 대한 계약은 서로 다른 TransactionFlowOption 설정을 보여 주는 각 작업을 사용하여 다음과 같이 정의됩니다.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
double Add(double n1, double n2);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
double Subtract(double n1, double n2);
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
여기서는 처리될 순서대로 작업을 정의합니다.
Add연산 요청에는 흐름이 지정된 트랜잭션이 포함되어야 합니다.Subtract연산 요청에는 흐름이 지정된 트랜잭션이 포함될 수 있습니다.Multiply연산 요청에는 명시적으로 NotAllowed를 설정하여 흐름이 지정된 트랜잭션을 포함하지 않아야 합니다.Divide연산 요청에는TransactionFlow특성을 생략하여 흐름이 지정된 트랜잭션을 포함하지 않아야 합니다.
트랜잭션 흐름을 사용하려면 적합한 작업 특성과 함께 <transactionFlow> 속성이 활성화된 바인딩을 사용해야 합니다. 이 샘플의 서비스 구성에서는 메타데이터 교환 끝점뿐만 아니라 TCP 끝점과 HTTP 끝점을 노출합니다. TCP 끝점과 HTTP 끝점은 모두 다음과 같이 <transactionFlow> 속성이 활성화된 바인딩을 사용합니다.
<bindings>
<netTcpBinding>
<binding name="transactionalOleTransactionsTcpBinding"
transactionFlow="true"
transactionProtocol="OleTransactions"/>
</netTcpBinding>
<wsHttpBinding>
<binding name="transactionalWsatHttpBinding"
transactionFlow="true" />
</wsHttpBinding>
</bindings>
참고
시스템 제공 netTcpBinding을 사용하면 transactionProtocol을 지정할 수 있지만 시스템 제공 wsHttpBinding에서는 상호 운용성이 보다 뛰어난 WSAtomicTransactionOctober2004 프로토콜만 사용합니다. OleTransactions 프로토콜은 WCF(Windows Communication Foundation) 클라이언트에서만 사용할 수 있습니다.
ICalculator 인터페이스를 구현하는 클래스에 대한 모든 메서드의 TransactionScopeRequired 속성은 true로 설정되어 있습니다. 이 설정은 메서드 내에서 수행되는 모든 작업이 트랜잭션의 범위 내에서 발생하도록 선언합니다. 이 경우 수행되는 작업에는 로그 데이터베이스에 기록하는 작업이 포함됩니다. 작업 요청에 흐름이 지정된 트랜잭션이 포함되면 들어오는 트랜잭션의 범위 내에서 작업이 발생하거나 새 트랜잭션 범위가 자동으로 생성됩니다.
참고
TransactionScopeRequired 속성은 서비스 메서드 구현에 로컬인 동작을 정의하며 트랜잭션 흐름에 대한 클라이언트의 기능이나 요구 사항은 정의하지 않습니다.
// Service class that implements the service contract.
[ServiceBehavior(TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable)]
public class CalculatorService : ICalculator
{
[OperationBehavior(TransactionScopeRequired = true)]
public double Add(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Adding {0} to {1}", n1, n2));
return n1 + n2;
}
[OperationBehavior(TransactionScopeRequired = true)]
public double Subtract(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Subtracting {0} from {1}", n2, n1));
return n1 - n2;
}
[OperationBehavior(TransactionScopeRequired = true)]
public double Multiply(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Multiplying {0} by {1}", n1, n2));
return n1 * n2;
}
[OperationBehavior(TransactionScopeRequired = true)]
public double Divide(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Dividing {0} by {1}", n1, n2));
return n1 / n2;
}
// Logging method omitted for brevity
}
클라이언트에서 작업에 대한 서비스의 TransactionFlowOption 설정은 ICalculator 인터페이스에 대해 클라이언트에서 생성한 정의에 반영됩니다. 또한 서비스의 transactionFlow 속성 설정은 클라이언트의 응용 프로그램 구성에 반영됩니다. 클라이언트는 다음과 같이 적합한 endpointConfigurationName을 선택하여 전송 및 프로토콜을 선택할 수 있습니다.
// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");
참고
이 샘플의 실제 동작은 선택한 프로토콜이나 전송에 관계없이 동일합니다.
서비스에 대한 연결을 시작하면 클라이언트는 다음과 같이 서비스 작업에 대한 호출에 따라 TransactionScope를 만듭니다.
// Start a transaction scope
using (TransactionScope tx =
new TransactionScope(TransactionScopeOption.RequiresNew))
{
Console.WriteLine("Starting transaction");
// Call the Add service operation
// - generatedClient will flow the required active transaction
double value1 = 100.00D;
double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine(" Add({0},{1}) = {2}", value1, value2, result);
// Call the Subtract service operation
// - generatedClient will flow the allowed active transaction
value1 = 145.00D;
value2 = 76.54D;
result = client.Subtract(value1, value2);
Console.WriteLine(" Subtract({0},{1}) = {2}", value1, value2, result);
// Start a transaction scope that suppresses the current transaction
using (TransactionScope txSuppress =
new TransactionScope(TransactionScopeOption.Suppress))
{
// Call the Subtract service operation
// - the active transaction is suppressed from the generatedClient
// and no transaction will flow
value1 = 21.05D;
value2 = 42.16D;
result = client.Subtract(value1, value2);
Console.WriteLine(" Subtract({0},{1}) = {2}", value1, value2, result);
// Complete the suppressed scope
txSuppress.Complete();
}
// Call the Multiply service operation
// - generatedClient will not flow the active transaction
value1 = 9.00D;
value2 = 81.25D;
result = client.Multiply(value1, value2);
Console.WriteLine(" Multiply({0},{1}) = {2}", value1, value2, result);
// Call the Divide service operation.
// - generatedClient will not flow the active transaction
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine(" Divide({0},{1}) = {2}", value1, value2, result);
// Complete the transaction scope
Console.WriteLine(" Completing transaction");
tx.Complete();
}
Console.WriteLine("Transaction committed");
다음과 같이 작업이 호출됩니다.
Add요청에서 필요한 트랜잭션의 흐름을 서비스로 지정하고 서비스의 작업은 클라이언트의 트랜잭션 범위 내에서 발생합니다.- 첫 번째
Subtract요청에서도 허용된 트랜잭션의 흐름을 서비스로 지정하고 서비스의 작업도 클라이언트의 트랜잭션 범위 내에서 발생합니다. - 두 번째
Subtract요청은 TransactionScopeOption.Suppress 옵션으로 선언된 새 트랜잭션 범위 내에서 수행됩니다. 따라서 클라이언트의 초기 외부 트랜잭션이 표시되지 않고 요청에서 트랜잭션의 흐름을 서비스로 지정하지 않습니다. 이 접근 방식을 사용하면 필요하지 않은 경우 클라이언트에서 트랜잭션 흐름이 실행되지 않도록 하고 트랜잭션 흐름이 서비스로 지정되지 않도록 보호할 수 있습니다. 서비스의 작업은 새 트랜잭션과 연결되지 않은 트랜잭션의 범위 내에서 발생합니다. Multiply요청에서는ICalculator인터페이스에 대해 클라이언트에서 생성한 정의에 TransactionFlowOption이 NotAllowed로 설정된 TransactionFlowAttribute가 포함되므로 트랜잭션의 흐름을 서비스로 지정하지 않습니다.Divide요청에서도ICalculator인터페이스에 대해 클라이언트에서 생성한 정의에 TransactionFlowAttribute가 포함되지 않으므로 트랜잭션의 흐름을 서비스로 지정하지 않습니다. 또한 서비스의 작업은 또 다른 새 트랜잭션과 연결되지 않은 트랜잭션의 범위 내에서 발생합니다.
샘플을 실행하면 작업 요청 및 응답이 클라이언트 콘솔 창에 표시됩니다. 클라이언트를 종료하려면 클라이언트 창에서 Enter 키를 누릅니다.
Starting transaction
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Subtract(21.05,42.16) = -21.11
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714
Completing transaction
Transaction committed
Press <ENTER> to terminate client.
서비스 작업 요청의 로깅은 서비스의 콘솔 창에 표시됩니다. 클라이언트를 종료하려면 클라이언트 창에서 Enter 키를 누릅니다.
Press <ENTER> to terminate the service.
Writing row to database: Adding 100 to 15.99
Writing row to database: Subtracting 76.54 from 145
Writing row to database: Subtracting 42.16 from 21.05
Writing row to database: Multiplying 9 by 81.25
Writing row to database: Dividing 22 by 7
성공적으로 실행되면 클라이언트의 트랜잭션 범위가 완료되고 해당 범위 내에서 수행된 모든 작업이 커밋됩니다. 특히 표시된 레코드 다섯 개는 서비스의 데이터베이스에 유지됩니다. 이러한 레코드 중 처음 두 개는 클라이언트의 트랜잭션 범위 내에서 발생한 것입니다.
클라이언트의 TransactionScope 내 임의 지점에서 예외가 발생하면 트랜잭션이 완료되지 않습니다. 따라서 레코드는 데이터베이스로 커밋되지 않고 해당 범위 내에서 기록됩니다. 이 효과는 호출을 주석으로 처리하여 외부 TransactionScope를 완료한 후 샘플 실행을 반복하여 확인할 수 있습니다. 이러한 실행에서는 클라이언트 트랜잭션의 흐름이 마지막 세 연산으로 지정되지 않기 때문에 해당 연산(두 번째 Subtract, Multiply 및 Divide 요청)만 기록됩니다.
샘플을 설치, 빌드 및 실행하려면
SQL Server 2005 Express Edition 또는 SQL Server 2005를 설치했는지 확인합니다. 서비스의 App.config 파일에서 데이터베이스 connectionString을 설정하거나 appSettings usingSql 값을 false로 설정하여 데이터베이스 상호 작용을 비활성화할 수 있습니다.
C# 또는 Visual Basic .NET 버전의 솔루션을 빌드하려면 Windows Communication Foundation 샘플 빌드의 지침을 따릅니다.
Windows SDK의 WsatConfig.exe 도구를 사용하여 WCF 트랜잭션 네트워크 지원을 활성화합니다.
단일 컴퓨터 또는 다중 컴퓨터 구성에서 샘플을 실행하려면 Windows Communication Foundation 샘플 실행의 지침을 따릅니다.
한 컴퓨터에서 샘플을 실행하는지 아니면 여러 컴퓨터에서 샘플을 실행하는지 여부에 관계없이 네트워크 트랜잭션 흐름을 활성화하도록 Microsoft Distributed Transaction Coordinator(MSDTC)를 구성하고 WsatConfig.exe 도구를 사용하여 WCF 트랜잭션 네트워크 지원을 활성화해야 합니다.
샘플을 실행할 수 있도록 Microsoft Distributed Transaction Coordinator(MSDTC)를 구성하려면
서비스 컴퓨터에서 들어오는 네트워크 트랜잭션을 허용하도록 MSDTC를 구성합니다.
- 시작 메뉴에서 제어판으로 이동한 다음 관리 도구를 선택하고 구성 요소 서비스를 선택합니다.
- 컴퓨터 폴더를 엽니다.
- 내 컴퓨터를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.
- MSDTC 탭에서 보안 구성을 클릭합니다.
- 네트워크 DTC 액세스 및 인바운드 허용을 선택합니다.
- 확인을 클릭한 다음 예를 클릭하여 MSDTC 서비스를 다시 시작합니다.
- 확인을 클릭하여 대화 상자를 닫습니다.
서비스 컴퓨터와 클라이언트 컴퓨터에서 예외 응용 프로그램 목록에 Microsoft Distributed Transaction Coordinator(MSDTC)가 포함되도록 Windows 방화벽을 구성합니다.
- 제어판에서 Windows 방화벽 응용 프로그램을 실행합니다.
- 예외 탭에서 프로그램 추가를 클릭합니다.
- C:\WINDOWS\System32 폴더로 이동합니다.
- Msdtc.exe를 선택하고 열기를 클릭합니다.
- 확인을 클릭하여 프로그램 추가 대화 상자를 닫고 확인을 다시 클릭하여 Windows 방화벽 애플릿을 닫습니다.
클라이언트 컴퓨터에서 나가는 네트워크 트랜잭션을 허용하도록 MSDTC를 구성합니다.
- 시작 메뉴에서 Control Panel으로 이동한 다음 관리 도구를 선택하고 구성 요소 서비스를 선택합니다.
- 내 컴퓨터를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.
- MSDTC 탭에서 보안 구성을 클릭합니다.
- 네트워크 DTC 액세스 및 아웃바운드 허용을 선택합니다.
- 확인을 클릭한 다음 예를 클릭하여 MSDTC 서비스를 다시 시작합니다.
- 확인을 클릭하여 대화 상자를 닫습니다.
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.