Compartilhar via


Fluxo de transação WS

A amostra TransactionFlow demonstra o uso de uma transação coordenada pelo cliente e as opções de cliente e servidor para fluxo de transações usando o protocolo WS-Atomic Transaction ou OleTransactions. Esta amostra baseia-se na Introdução que implementa um serviço de calculadora, mas as operações são atribuídas para demonstrar o uso de TransactionFlowAttribute com a enumeração TransactionFlowOption para determinar em que grau o fluxo de transação está habilitado. No escopo da transação fluida, um log das operações solicitadas é gravado em um banco de dados e persiste até que a transação coordenada pelo cliente seja concluída – se a transação do cliente não for concluída, a transação do serviço Web garantirá que as atualizações apropriadas para o banco de dados não sejam confirmadas.

Observação

O procedimento de instalação e as instruções de compilação dessa amostra estão no final deste tópico.

Depois de iniciar uma conexão com o serviço e uma transação, o cliente acessa várias operações de serviço. O contrato para o serviço é definido da seguinte maneira com cada uma das operações demonstrando uma configuração diferente para o 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);
}

Isso define as operações na ordem em que elas devem ser processadas:

  • Uma solicitação de operação Add deve incluir uma transação fluída.

  • Uma solicitação de operação Subtract pode incluir uma transação fluída.

  • Uma solicitação de operação Multiply não deve incluir uma transação fluida pela configuração explícita NotAllowed.

  • Uma solicitação de operação Divide não deve incluir uma transação fluida pela omissão de um atributo TransactionFlow.

Para habilitar o fluxo de transações, as associações com a propriedade <transactionFlow> habilitada devem ser usadas além dos atributos de operação apropriados. Nesta amostra, a configuração do serviço expõe um ponto de extremidade TCP e um ponto de extremidade HTTP, além de um ponto de extremidade do Metadata Exchange. O ponto de extremidade TCP e o ponto de extremidade HTTP usam as associações a seguir, ambas com a propriedade <transactionFlow> habilitada.

<bindings>
  <netTcpBinding>
    <binding name="transactionalOleTransactionsTcpBinding"
             transactionFlow="true"
             transactionProtocol="OleTransactions"/>
  </netTcpBinding>
  <wsHttpBinding>
    <binding name="transactionalWsatHttpBinding"
             transactionFlow="true" />
  </wsHttpBinding>
</bindings>

Observação

O netTcpBinding fornecido pelo sistema permite a especificação do transactionProtocol, enquanto o wsHttpBinding fornecido pelo sistema usa apenas o protocolo WSAtomicTransactionOctober2004 mais interoperável. O protocolo OleTransactions só está disponível para uso por clientes do WCF (Windows Communication Foundation).

Na classe que implementa a interface ICalculator, todos os métodos são atribuídos com a propriedade TransactionScopeRequired definida como true. Essa configuração declara que todas as ações executadas no método ocorrem dentro do escopo de uma transação. Nesse caso, as ações executadas incluem a gravação no banco de dados de log. Se a solicitação de operação incluir uma transação fluída, as ações ocorrerão no escopo da transação de entrada ou um novo escopo de transação será gerado automaticamente.

Observação

A propriedade TransactionScopeRequired define o comportamento local para as implementações do método de serviço e não define a capacidade ou requisito do cliente para o fluxo de uma transação.

// 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
}

No cliente, as configurações TransactionFlowOption do serviço nas operações são refletidas na definição gerada pelo cliente da interface ICalculator. Além disso, as configurações de propriedade transactionFlow do serviço são refletidas na configuração do aplicativo do cliente. O cliente pode selecionar o transporte e o protocolo selecionando o endpointConfigurationName apropriado.

// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");

Observação

O comportamento observado dessa amostra é o mesmo, independentemente de qual protocolo ou transporte seja escolhido.

Depois de iniciar a conexão com o serviço, o cliente cria um novo TransactionScope em torno das chamadas para as operações de serviço.

// 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");

As chamadas para as operações são as seguintes:

  • A solicitação Add flui a transação necessária para o serviço e as ações do serviço ocorrem no escopo da transação do cliente.

  • A primeira solicitação Subtract também flui a transação permitida para o serviço e as ações do serviço ocorrem novamente no escopo da transação do cliente.

  • A segunda solicitação Subtract é executada em um novo escopo de transação declarado com a opção TransactionScopeOption.Suppress. Isso suprime a transação externa inicial do cliente e a solicitação não flui uma transação para o serviço. Essa abordagem permite que um cliente recuse explicitamente e proteja contra o fluxo de uma transação para um serviço quando isso não for necessário. As ações do serviço ocorrem no escopo de uma transação nova e não conectada.

  • A solicitação Multiply não flui uma transação para o serviço porque a definição gerada do cliente da interface ICalculator inclui um conjunto TransactionFlowAttribute para TransactionFlowOptionNotAllowed.

  • A solicitação Divide não flui uma transação para o serviço porque a definição gerada do cliente da interface ICalculator não inclui um conjunto TransactionFlowAttribute. As ações do serviço ocorrem novamente no escopo de outra transação nova e não conectada.

Quando você executa a amostra, as solicitações de operação e as respostas são exibidas na janela do console do cliente. Pressione ENTER na janela do cliente para desligar o cliente.

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.

O log das solicitações de operação de serviço é exibido na janela do console do serviço. Pressione ENTER na janela do cliente para desligar o cliente.

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

Após uma execução bem-sucedida, o escopo da transação do cliente é concluído e todas as ações executadas dentro desse escopo são confirmadas. Especificamente, os 5 registros anotados são persistentes no banco de dados do serviço. Os dois primeiros ocorreram no escopo da transação do cliente.

Se uma exceção ocorreu em qualquer lugar no TransactionScope do cliente, a transação não poderá ser concluída. Isso faz com que os registros nesse escopo não sejam confirmados no banco de dados. Esse efeito pode ser observado repetindo a execução de exemplo depois de comentar a chamada para concluir o TransactionScope exterior. Nessa execução, somente as três últimas ações (do segundo Subtract, do Multiply e das solicitações Divide) são registradas porque a transação do cliente não fluiu para elas.

Para configurar, compilar, e executar o exemplo

  1. Para compilar a versão C# ou do Visual Basic .NET da solução, siga as instruções em Como compilar as amostras do Windows Communication Foundation

  2. Verifique se você instalou o SQL Server Express Edition ou o SQL Server e se a cadeia de conexão foi definida corretamente no arquivo de configuração de aplicativo do serviço. Para executar a amostra sem usar um banco de dados, defina o valor usingSql no arquivo de configuração de aplicativo do serviço como false

  3. Para executar a amostra em uma configuração de computador único ou entre computadores, siga as instruções contidas em Como Executar as Amostras do Windows Communication Foundation.

    Observação

    Para configuração entre computadores, habilite o Coordenador de Transações Distribuídas usando as instruções abaixo e use a ferramenta WsatConfig.exe do SDK do Windows para habilitar o suporte à rede WCF Transactions. Para obter informações sobre como configurar o WsatConfig.exe, consulte Configurando o suporte a transações do WS-Atomic.

Se você executar a amostra no mesmo computador ou em computadores diferentes, deverá configurar o MSDTC (Coordenador de Transações Distribuídas da Microsoft) para habilitar o fluxo de transações de rede e usar a ferramenta WsatConfig.exe para habilitar o suporte à rede de transações do WCF.

Para configurar o MSDTC (Coordenador de Transações Distribuídas da Microsoft) para dar suporte à execução da amostra

  1. Em um computador de serviço que executa o Windows Server 2003 ou Windows XP, configure o MSDTC para permitir transações de rede de entrada seguindo estas instruções.

    1. No menu Iniciar, navegue até Painel de Controle, Ferramentas Administrativas e, em seguida, Serviços de Componentes.

    2. Expanda Serviços de Componentes. Abra a pasta Computadores.

    3. Clique com o botão direito do mouse em Meu Computador e, em seguida, selecione Propriedades.

    4. Na guia MSDTC, clique em Configuração de Segurança.

    5. Verifique o Acesso do DTC de Rede e Permita a entrada.

    6. Clique em OK e, em seguida, Sim para reiniciar o serviço MSDTC.

    7. Clique em OK para fechar a caixa de diálogo.

  2. Em um computador de serviço que executa o Windows Server 2008 ou Windows Vista, configure o MSDTC para permitir transações de rede de entrada seguindo estas instruções.

    1. No menu Iniciar, navegue até Painel de Controle, Ferramentas Administrativas e, em seguida, Serviços de Componentes.

    2. Expanda Serviços de Componentes. Abra a pasta Computadores. Selecione Coordenador de Transações Distribuídas.

    3. Clique com o botão direito do mouse e, Coordenador do DTC e selecione Propriedades.

    4. Na guia Segurança, verifique o Acesso do DTC de Rede e Permita a entrada.

    5. Clique em OK e, em seguida, Sim para reiniciar o serviço MSDTC.

    6. Clique em OK para fechar a caixa de diálogo.

  3. No computador cliente, configure o MSDTC para permitir transações de rede de saída:

    1. No menu Iniciar, navegue até Control Panel, Ferramentas Administrativas e, em seguida, Serviços de Componentes.

    2. Clique com o botão direito do mouse em Meu Computador e, em seguida, selecione Propriedades.

    3. Na guia MSDTC, clique em Configuração de Segurança.

    4. Verifique o Acesso do DTC de Rede e Permita a saída.

    5. Clique em OK e, em seguida, Sim para reiniciar o serviço MSDTC.

    6. Clique em OK para fechar a caixa de diálogo.