Поток транзакций WS
Пример TransactionFlow демонстрирует использование транзакции, координируемой клиентом, а также параметры настройки потока транзакций для клиента и сервера с помощью протокола WS-Atomic Transaction или OleTransactions. Этот пример основан на Getting Started, который реализует службу калькулятора, но операции специально предназначены для демонстрации использования TransactionFlowAttribute
с перечислением TransactionFlowOption, чтобы определить степень, в которой поток транзакций включен. В пределах потоковой транзакции журнал запрошенных операций записывается в базу данных и сохраняется до тех пор, пока клиентская транзакция не завершится. Если транзакция клиента не завершится, транзакция веб-службы гарантирует, что соответствующие обновления базы данных не зафиксированы.
Заметка
Процедура установки и инструкции по сборке для этого примера находятся в конце этого раздела.
После инициирования подключения к службе и транзакции клиент обращается к нескольким операциям службы. Контракт услуги определяется следующим образом: каждая из операций демонстрирует различную настройку для 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 в дополнение к конечной точке Exchange метаданных. Конечная точка 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 доступен только для использования клиентами Windows Communication Foundation (WCF).
Для класса, реализующего интерфейс 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
, созданное клиентом, включает TransactionFlowAttribute, установленный в TransactionFlowOptionNotAllowed
.Запрос
Divide
не инициирует транзакцию в службу, так как вновь определенное клиентом определение интерфейсаICalculator
не включаетTransactionFlowAttribute
. Действия службы снова происходят в рамках новой другой и несвязанной транзакции.
При запуске примера запросы и ответы операции отображаются в окне консоли клиента. Нажмите клавишу ВВОД в окне клиента, чтобы завершить работу клиента.
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.
Логирование запросов на операции службы отображается в окне консоли этой службы. Нажмите клавишу ВВОД в окне клиента, чтобы завершить работу клиента.
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
После успешного выполнения область транзакции клиента завершается, и все действия, осуществленные в этой области, фиксируются. В частности, указанные 5 записей сохраняются в базе данных службы. Первые 2 из них произошли в пределах области транзакции клиента.
Если исключение произошло в любом месте TransactionScope
клиента, транзакция не может завершиться. Это приводит к тому, что записи, зарегистрированные в этой области, не будут зафиксированы в базе данных. Этот эффект можно наблюдать, повторяя этот пример выполнения после закомментирования вызова, чтобы завершить внешний TransactionScope
. При таком выполнении регистрируются только последние 3 действия (из второго Subtract
, Multiply
и Divide
запросов), так как транзакция клиента не перетекала в них.
Настройка, сборка и запуск примера
Чтобы создать версию решения на C# или Visual Basic . NET, следуйте инструкциям в создании примеров Windows Communication Foundation.
Убедитесь, что вы установили SQL Server Express Edition или SQL Server и правильно установили строку подключения в файле конфигурации приложения службы. Чтобы запустить пример без использования базы данных, задайте значение
usingSql
в файле конфигурации приложения службыfalse
.Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в запуска примеров Windows Communication Foundation.
Заметка
Для настройки между компьютерами включите координатор распределенных транзакций с помощью приведенных ниже инструкций и используйте средство WsatConfig.exe из пакета SDK для Windows, чтобы включить поддержку сети транзакций WCF. Сведения о настройке WsatConfig.exeсм. в разделе Настройка WS-Atomic поддержки транзакций.
Независимо от того, выполняется ли пример на одном компьютере или на разных компьютерах, необходимо настроить координатор распределенных транзакций Майкрософт (MSDTC), чтобы включить поток сетевых транзакций и использовать средство WsatConfig.exe для включения поддержки сети транзакций WCF.
Настройка координатора распределенных транзакций Майкрософт (MSDTC) для поддержки выполнения примера
На компьютере службы под управлением Windows Server 2003 или Windows XP настройте MSDTC, чтобы разрешить входящие сетевые транзакции, следуя этим инструкциям.
В меню "Пуск" перейдите к "Панели управления", затем "Административные инструменты", и затем "Службы компонентов".
Разверните службы компонентов. Откройте папку Компьютеры.
Щелкните правой кнопкой мыши "Мой компьютер" и выберите Свойства.
На вкладке MSDTC щелкните Конфигурация безопасности.
Проверьте доступ к сети DTC и разрешите входящие.
Нажмите кнопку ОК, а затем нажмите кнопку Да, чтобы перезапустить службу MSDTC.
Нажмите кнопку ОК, чтобы закрыть диалоговое окно.
На компьютере службы под управлением Windows Server 2008 или Windows Vista настройте MSDTC, чтобы разрешить входящие сетевые транзакции, следуя этим инструкциям.
В меню "Пуск" откройте "Панель управления", затем "Административные инструменты", и после этого "Службы компонентов".
Разверните службы компонентов. Откройте папку Computers. Выберите координатор распределенных транзакций.
Щелкните правой кнопкой мыши координатор DTC и выберите Свойства.
На вкладке "Безопасность" проверьте "Доступ к сети DTC" и "Разрешить входящий".
Нажмите кнопку ОК, а затем нажмите кнопку Да, чтобы перезапустить службу MSDTC.
Нажмите кнопку ОК, чтобы закрыть диалоговое окно.
На клиентском компьютере настройте MSDTC, чтобы разрешить исходящие сетевые транзакции:
В меню "Пуск" перейдите к
Control Panel
, затем Администрирование, а затем к Службы компонентов.Щелкните правой кнопкой мыши на "Мой компьютер" и выберите "Свойства".
На вкладке MSDTC щелкните Конфигурация безопасности.
Проверьте доступ к сети DTC и Разрешите исходящие.
Нажмите кнопку ОК, а затем нажмите кнопку Да, чтобы перезапустить службу MSDTC.
Нажмите кнопку ОК, чтобы закрыть диалоговое окно.