Partilhar via


Fluxo de transações WS

O exemplo TransactionFlow demonstra o uso de uma transação coordenada pelo cliente e as opções do cliente e do servidor para o fluxo de transações usando o protocolo WS-Atomic Transaction ou OleTransactions. Este exemplo é baseado na Introdução que implementa um serviço de calculadora, mas as operações são atribuídas para demonstrar o uso do com a enumeração TransactionFlowOption para determinar até que ponto o TransactionFlowAttribute fluxo de transações está habilitado. Dentro do escopo da transação fluída, 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 garante que as atualizações apropriadas para o banco de dados não sejam confirmadas.

Nota

O procedimento de configuração e as instruções de compilação para este exemplo estão localizados 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 forma, 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);
}

Isto define as operações pela ordem em que devem ser processadas:

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

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

  • Uma Multiply solicitação de operação não deve incluir uma transação fluída por meio da configuração explícita NotAllowed.

  • Uma Divide solicitação de operação não deve incluir uma transação fluída através da omissão de um TransactionFlow atributo.

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. Neste exemplo, 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 seguintes associações, ambas com a <propriedade transactionFlow> habilitada.

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

Nota

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 Windows Communication Foundation (WCF).

Para a classe que implementa a ICalculator interface, todos os métodos são atribuídos com TransactionScopeRequired a propriedade definida como true. Essa configuração declara que todas as ações tomadas dentro do método ocorrem dentro do escopo de uma transação. Nesse caso, as ações tomadas 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 dentro do escopo da transação de entrada ou um novo escopo de transação será gerado automaticamente.

Nota

A TransactionScopeRequired propriedade define o comportamento local para as implementações do método de serviço e não define a capacidade ou o requisito do cliente para fluir 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 do TransactionFlowOption serviço nas operações são refletidas na definição gerada pelo cliente da ICalculator interface. Além disso, as configurações de transactionFlow propriedade do serviço são refletidas na configuração do aplicativo do cliente. O cliente pode selecionar o transporte e protocolo, selecionando o apropriado endpointConfigurationName.

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

Nota

O comportamento observado desta amostra é o mesmo, independentemente do protocolo ou transporte escolhido.

Tendo iniciado a conexão com o serviço, o cliente cria uma nova 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 Add solicitação flui a transação necessária para o serviço e as ações do serviço ocorrem dentro do escopo da transação do cliente.

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

  • A segunda Subtract solicitação é realizada dentro de um novo escopo de transação declarado com a TransactionScopeOption.Suppress opção. 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 opte explicitamente por não participar e se 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 âmbito de uma transação nova e desconexa.

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

  • A Divide solicitação não flui uma transação para o serviço porque, novamente, a definição gerada pelo cliente da ICalculator interface não inclui um TransactionFlowAttributearquivo . As ações do serviço ocorrem novamente no âmbito de outra transação nova e desconexa.

Quando você executa o exemplo, 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 registro 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 tomadas dentro desse escopo são confirmadas. Especificamente, os 5 registros anotados são mantidos no banco de dados do serviço. Os 2 primeiros ocorreram no âmbito da transação do cliente.

Se uma exceção ocorreu em qualquer lugar dentro do TransactionScope cliente, a transação não pode ser concluída. Isso faz com que os registros registrados nesse escopo não sejam confirmados no banco de dados. Este efeito pode ser observado repetindo a execução de amostra depois de comentar a chamada para concluir o .TransactionScope Em tal execução, apenas as últimas 3 ações (a partir da segunda Subtract, a Multiply e as Divide solicitações) são registradas porque a transação do cliente não fluiu para elas.

Para configurar, compilar e executar o exemplo

  1. Para criar a versão C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos 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 do aplicativo do serviço. Para executar o exemplo sem usar um banco de dados, defina o usingSql valor no arquivo de configuração do aplicativo do serviço como false

  3. Para executar o exemplo em uma configuração de máquina única ou cruzada, siga as instruções em Executando os exemplos do Windows Communication Foundation.

    Nota

    Para configuração entre máquinas, 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 de Transações WCF. Para obter informações sobre como configurar o WsatConfig.exe, consulte Configurando o suporte a transações WS-Atomic .

Se você executar o exemplo no mesmo computador ou em computadores diferentes, você deve configurar o Microsoft Distributed Transaction Coordinator (MSDTC) para habilitar o fluxo de transações de rede e usar a ferramenta WsatConfig.exe para habilitar o suporte de rede de transações WCF.

Para configurar o Microsoft Distributed Transaction Coordinator (MSDTC) para suportar a execução do exemplo

  1. Em uma máquina de serviço que executa o Windows Server 2003 ou o 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 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 selecione Propriedades.

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

    5. Verifique Acesso DTC à rede e Permitir entrada.

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

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

  2. Em uma máquina de serviço que executa o Windows Server 2008 ou o 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 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 em Coordenador DTC e selecione Propriedades.

    4. Na guia Segurança, marque Acesso DTC à Rede e Permitir Entrada.

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

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

  3. Na máquina cliente, configure o MSDTC para permitir transações de rede de saída:

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

    2. Clique com o botão direito do mouse em Meu computador e selecione Propriedades.

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

    4. Marque Acesso DTC à Rede e Permitir Saída.

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

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