Este artigo foi traduzido por máquina.

Padrões em nuvem

Criação de serviços para Windows Azure

Thomas Erl

Baixe o código de exemplo

Windows Azure é uma plataforma de computação em nuvem novo em desenvolvimento pela Microsoft (de microsoft.com/windowsazure ).Computação permite que os desenvolvedores de aplicativos de host em um ambiente virtual acessível pela Internet em nuvem.O ambiente de forma transparente fornece hardware, software, rede e armazenamento necessários ao aplicativo.

Como com outros ambientes de nuvem Windows Azure fornece um ambiente hospedado para aplicativos.O benefício adicional do Windows Azure é que os aplicativos podem ser implantados com alterações mínimas de seus irmãos desktops do .NET Framework.

Aplicar padrões de arquitetura orientada a serviços (SOA) e utilizando as experiências coletados quando a implementação de soluções orientadas a serviços será uma chave do sucesso quando movendo seus serviços e aplicativos para o novo arena de nuvem de computação.Para entender melhor como SOA padrões podem ser aplicadas às implantações do Windows Azure, let’s dar uma olhada em uma situação na qual um banco fictício move seus serviços à nuvem.

Nuvem bancário

O Woodgrove Bank é uma instituição financeira pequena que decidiu se concentrar em uma nova iniciativa de banco on-line da marca on-line do Woodgrove Bank.Um dos clientes mais importantes do Woodgrove Bank, Fourth Coffee foram experimentar a nova solução para o processamento de transações de cartão.Um subconjunto dos serviços planejado para a solução já está em tempo real e a disponibilidade desses serviços gerou mais interesse de outros clientes.No entanto, como mais de implementação da solução é planejado, surgem desafios.

O primeiro problema pertence a escalabilidade e confiabilidade.O Woodgrove Bank nunca queria assumir a responsabilidade para hospedar suas soluções de TI.Em vez disso, ela estabeleceu um acordo de aprovisionamento com um ISP local chamado a empresa de hospedagem Sesame.Até hoje, hospedagem Sesame atendeu a necessidades do Woodgrove Bank de hospedagem na Web, mas a nova solução de processamento cartão introduziu os requisitos de escalabilidade Sesame host não está preparada para manipular.

A equipe de arquitetura de tecnologia do Woodgrove Bank sugere redundância implantar os serviços online do Woodgrove Bank, de acordo com o padrão de implementação redundante (descrições dos padrões abordados aqui podem ser encontradas em soapatterns.org).Em essência, o padrão sugere uma abordagem na qual serviços intencionalmente implantados redundância para maior escalabilidade e failover.A empresa de hospedagem Sesame investiga essa opção, mas não pode expandir a infra-estrutura para acomodar implantações serviço redundantes.Ele simplesmente não tem os recursos ou o orçamento para tratar o aumento em hardware, manutenção de software operacionais e dispositivos que seriam necessários de rede.

O intervalo de tempo também é um problema.Mesmo se Sesame Hosting pode disponibilizar a infra-estrutura necessária, ele pode não fazê-lo in-time para o Woodgrove Bank atender a sua agenda de transferência planejada.A necessidade de contratar e treinar pessoal sozinho pode prolongar a expansão de infra-estrutura muito além dos horários disponíveis do Woodgrove Bank.

Depois de perceber que Sesame Hosting seria capaz de atender às suas necessidades, a equipe do Woodgrove Bank começa a explorar a opção de hospedar seus serviços em uma nuvem pública.A plataforma Windows Azure fornece uma maneira de serviços de virtualização que naturalmente aplicar o padrão de implementação redundante.Esse recurso do Windows Azure é chamado de instância de aplicação sob demanda ( discutido em maio de 2009 ).Este recurso e a capacidade de usar o Microsoft Data centers sem compromisso de longo prazo, parece promissor para a equipe do Woodgrove Bank.Let’s dê uma olhada mais de perto como o Woodgrove Bank migra sua solução para Windows Azure.

Noções básicas de implantação

A prioritária é implantar um serviço da Web seguindo uma abordagem Contratar primeiro que estejam de acordo com o princípio de contrato de serviço padronizado.A equipe usa a ferramenta WSCF.blue para gerar contratos do WCF (Windows Communication Foundation) a partir de WSDL e XSDs foram modelados para interoperabilidade ideal.Contratos de serviço são mostrados em 1 Figura .

Figura 1 os contratos de serviço inicial

image: The Initial Service Contracts

Como os serviços precisam mudar e evoluir ao longo do tempo, os desenvolvedores também decidem permitir que seus contratos de dados implementam a interface IExtensibleObject em suporte de padrão compatibilidade direta (consulte do Figura 2).

Figura 2 os contratos de dados inicial

image: The Initial Data Contracts

Para armazenar os dados necessários, a equipe do Woodgrove Bank deseja usar SQL Azure porque já possui uma estrutura de banco de dados existente, a equipe deseja manter.Se os desenvolvedores podem usar um armazenamento não-relacional, eles talvez em vez disso, considere Windows Azure Storage.

Arquitetos do Woodgrove Bank vá para criar um serviço de nuvem modelo Visual Studio e usar o Visual Studio para publicá-lo.Fizerem logon, em seguida, em Windows Azure portal para criar seu novo serviço em nuvem (consulte do Figura 3).

Figura 3 Criando um serviço do Windows Portal Azure

image: Creating a Service in the Azure Portal

Em seguida, são apresentados com uma tela que permite que eles iniciar o serviço de implantação.Eles clique no botão Deploy e especifique um pacote de aplicativos, configurações e um nome de implantação.Após alguns cliques mais, seus serviços é que residem em nuvem.

Figura 4 mostra um exemplo de configuração do serviço.

Figura 4 de configuração do Windows Service Azure

<Role name="BankWebRole">
  <Instances count="1" />
  <ConfigurationSettings>
    <Setting 
      name="DataConnectionString" 
      value="DefaultEndpointsProtocol=https;AccountName=YOURACCOUNTNAME;AccountKey=YOURKEY" />
    <Setting 
      name="DiagnosticsConnectionString" 
      value="DefaultEndpointsProtocol=https;AccountName=YOURDIAGNOSTICSACCOUNTNAME;AccountKey=YOURKEY" />

A chave de fazendo a solução elástica com relação aos requisitos de escalabilidade do Woodgrove Bank é o elemento de configuração a seguir:

<Instances count="1" />

Por exemplo, se desejam que os desenvolvedores 10 instâncias, esse elemento seria definido como:

<Instances count="10" />

Figura 5 mostra a tela que confirma que apenas uma instância está em execução. Clicar no botão Configurar traz uma tela de onde estejam capazes de editar a configuração de serviço e alterar as instâncias como necessário.

Figura 5 instâncias running in Windows Azure

Desempenho e flexibilidade

Depois de enfatizar alguns testes, a equipe de desenvolvimento do Woodgrove Bank descobriu que ter somente um armazenamento de dados central em SQL Azure levou a tempos de resposta mais lentos e mais lento quando o tráfego aumenta. Os desenvolvedores decidiram resolver esse problema de desempenho usando o Windows Azure tabela de armazenamento, projetada para melhorar a escalabilidade distribuindo as partições entre vários nós de armazenamento. Armazenamento de tabela Windows Azure também fornece acesso a dados rápidos porque o sistema monitora a utilização das partições e automaticamente carregar-saldos-los. No entanto, porque Windows Azure tabela armazenamento não é um armazenamento de dados relacional, a equipe tinha algumas novas estruturas de armazenamento de dados de design e escolher uma combinação de teclas de partição e a linha que poderia fornecer tempos de resposta de BOM.

Eles acabaram com três tabelas conforme mostrado no do Figura 6. UserAccountBalance armazenará os saldos da conta do usuário. AccountTransactionLogg será usado para armazenar todas as mensagens de transação para contas específicas. A tabela UserAccountTransaction será usada para armazenar as transações por conta. As chaves de partição para as tabelas UserAccountTransaction e AccountTransactionLogg foram criadas pela concatenação de UserId e AccountId porque eles são parte de todas as consultas e podem fornecer tempos de resposta rápida. A chave de partição para a tabela UserAccountBalance é UserId e a chave de linha é AccountId. Juntos, eles fornecem uma identificação exclusiva de um usuário e sua conta.

Figura 6 modelos de armazenamento de tabela Azure Windows

image: Azure Table Storage Models

O Woodgrove Bank considera o sucesso do projeto até o momento e quer mais clientes para começar a usar a solução. Em breve World Wide Importers está pronto para ingressar — embora com alguns novos requisitos funcionais.

A solicitação que parece mais importantes é que a interface do serviço (ou estrutura de informações) deve ser alterada. De acordo com a World Wide Importers, a estrutura de informações usada pelo Woodgrove Bank não é compatível com os produtos delas. Devido à importância desse determinado cliente, a equipe de desenvolvimento do Woodgrove Bank sugere a aplicação de padrão de transformação de modelo de dados. Os desenvolvedores criaria vários novos serviços com as interfaces World Wide Importers solicitada e esses serviços conteria lógica para traduzir as solicitações entre os modelos de World Wide importadores de dados e os modelos de dados do Woodgrove Bank.

Para atender a esse requisito, é criada uma nova estrutura para o Conta_de_usuário. Os desenvolvedores são cuidadosos para garantir que haja um mapeamento claro entre as classes UserAccountWwi e Conta_de_usuário, conforme mostrado no do Figura 7.

Figura 7 do Conta_de_usuário estrutura para o modelo de dados de transformação

image: UserAccount Structure for Data Model Transformation

Contratos de serviço necessário aceitar um contrato de dados específicos (UserAccountWwi) transforma as solicitações de Conta_de_usuário antes de passar na chamada para outras partes da solução e transforme-o novamente na resposta. Os arquitetos no Woodgrove Bank percebem que poderia reutilizar uma interface de serviço base ao implementar esses novos requisitos. Do Figura 8 mostra o design final.

Figura 8 contratos de serviço para World Wide Importers

image: Service Contracts for World Wide Importers

Os desenvolvedores optar por implementar as transformações de dados, criando alguns métodos de extensão para a classe Conta_de_usuário, incluindo os métodos TransformToUserAccountWwi e TransformToUserAccount.

O novo serviço aceita o contrato de dados UserAccountWwi. Antes para enviar solicitações para outras camadas, os dados são transformados Conta_de_usuário chamando o método de extensão TransformToUserAccount. Antes de enviar uma resposta ao consumidor, o contrato Conta_de_usuário é transformado para UserAccountWwi chamando o TransformToUserAccountWwi. Para obter detalhes sobre esses elementos ver o código-fonte para UserAccountServiceAdvanced no download do código deste artigo.

Mensagens e enfileiramento de mensagens

Embora o Woodgrove Bank cima e em execução e é capaz de facilitar a um grande número de solicitações de entrada agora, os analistas observou significativos picos no uso do serviço. Alguns desses picos veio regularmente (especificamente, mornings segunda-feira e quinta-feira afternoons). No entanto, alguns flutuações são imprevisíveis.

Colocar mais recursos on-line via Windows Azure configuração seria uma solução simples, mas agora que alguns clientes grandes, como World Wide Importers estão interessados em novos serviços, uso simultâneo flutuações deve aumentar.

Os desenvolvedores no Woodgrove Bank levava uma análise mais detalhada de ofertas de Windows Azure e descobrir recursos que permitem para o aplicativo dos padrões Reliable Messaging e enfileiramento de mensagens assíncronas. Eles concluiu que Reliable Messaging não era a escolha mais adequada conforme ele restringiria opções técnicos de seus clientes. Enfileiramento de mensagens assíncrono não requer nenhuma tecnologia especial de clientes para que teria se concentrar no que. Dentro da nuvem Windows Azure, entretanto, Reliable Messaging feitas sentido, já que a tecnologia utilizada lá foi fornecida pela Microsoft.

O objetivo é que nenhuma mensagem deve ser perdida, mesmo se os serviços estão off-line devido a condições de erro ou manutenção planejada. O padrão assíncrono Queuing permite isso, embora algumas ofertas não são adequadas para esse padrão. Por exemplo, solicitar respostas com confirmação ou uma negação de transferências de dinheiro são necessárias ao lidar com transações de cartão on-line. Mas em outras situações o padrão deve fazer bem.

A comunicação entre as funções de trabalho e da Web (consulte msdn.microsoft.com/magazine/dd727504 de para obter uma explicação sobre essas funções) é feita com Windows Azure filas (da versão CTP de novembro é possível se comunicar diretamente entre as instâncias da função), que são, por padrão, assíncrona e confiável. Isso não significa automaticamente que a comunicação entre o usuário final e serviços do Woodgrove Bank é confiável. Na verdade, as linhas de comunicação entre o cliente e os serviços que residem na função Web são claramente não confiáveis. A equipe do Woodgrove Bank decidiu não tratar isso como implementar mecanismos de confiabilidade até os clientes seria prática exigem os clientes a cumprir as mesmas opções tecnológicas como o Woodgrove Bank. Isso era considerado irreal e indesejáveis.

Colocar filas de trabalho

Assim que um cliente envia uma mensagem para UserAccountService, esta mensagem é colocada em uma fila de Azure Windows e o cliente recebe uma mensagem de confirmação. UserAccountWorker poderá receber a mensagem da fila. UserAccountWorker deve estar desativado, a mensagem não serão perdida quando eles são armazenados com segurança na fila.

Se o processamento dentro UserAccountWorker der errado, a mensagem não será removida da fila. Para garantir isso, a chamada ao método DeleteMessage da fila é feita somente após a conclusão do trabalho. Se UserAccountWorker não terminou de processar a mensagem antes do tempo limite (o tempo limite é codificado para 20 segundos), a mensagem novamente ficará visível na fila para que outra instância do UserAccountWorker pode tentar processá-lo.

Assim que um cliente envia uma mensagem para UserAccountService, esta mensagem é colocada em uma fila e o cliente recebe uma mensagem de confirmação do tipo TransactionResponse. Do ponto de vista do cliente, enfileiramento de mensagens assíncronas é usado. ReliableMessaging é usado para se comunicar entre UserAccountStorageAction e AccountStorageWorker, que residem na função de Web e função de trabalho, respectivamente. Eis como o manipulador de chamada colocar mensagens em fila:

public TransactionResponse ReliableInsertMoney(
  AccountTransactionRequest accountTransactionrequest) {

//last parameter (true) means that we want to serialize
//message to the queue as XML (serializeAsXml=true)
  return UserAccountHandler.ReliableInsertMoney(
    accounttransactionRequest.UserId, 
    accounttransactionRequest.AccountId, 
    accounttransactionRequest.Amount, true);
}

UserAccountHandler é uma propriedade que retorna um IUserAccountAction, que é injetada no ambiente de execução. Isso torna mais fácil separar a implementação do contrato e alterar posteriormente a implementação:

public IUserAccountAction<Models.UserAccount> UserAccountHandler
  {get;set;}

public UserAccountService(
  IUserAccountAction<Models.UserAccount> action) {

  UserAccountHandler = action;
}

Depois que a mensagem for enviada a uma das ações responsáveis, ele será colocado na fila. O primeiro método em do Figura 9 mostra como os dados podem ser armazenados como XML pode ser serializado e o segundo método mostra como os dados podem ser armazenados como uma seqüência de caracteres na fila. Observe que há uma limitação no Windows Azure filas em que o tamanho máximo da mensagem é 8 KB.

Figura 9 de armazenar dados

public TransactionResponse ReliableHandleMoneyInQueueAsXml( 
  UserAccountTransaction accountTransaction){ 

  using (MemoryStream m = new MemoryStream()){ 
    XmlSerializer xs = 
      new XmlSerializer(typeof(UserAccountTransaction)); 
    xs.Serialize(m, accountTransaction); 

    try 
    { 
      QueueManager.AccountTransactionsQueue.AddMessage( 
        new CloudQueueMessage(m.ToArray())); 
      response.StatusForTransaction = TransactionStatus.Succeded; 
    } 
    catch(StorageClientException) 
    { 
      response.StatusForTransaction = TransactionStatus.Failed; 
      response.Message = 
        String.Format("Unable to insert message in the account transaction queue userId|AccountId={0}, messageId={1}", 
        accountTransaction.PartitionKey, accountTransaction.RowKey); 
    } 
  } 
  return response; 
} 

public TransactionResponse ReliableHandleMoneyInQueue( 
  UserAccountTransaction accountTransaction){ 

  TransactionResponse response = this.CheckIfTransactionExists( 
    accountTransaction.PartitionKey, accountTransaction.RowKey); 
       
  if (response.StatusForTransaction == TransactionStatus.Proceed) 
  { 
    //userid|accountid is partkey 
    //userid|accountid|transactionid|amount 
    string msg = string.Format("{0}|{1}|{2}", 
      accountTransaction.PartitionKey, 
      accountTransaction.RowKey, 
      accountTransaction.Amount); 

    try 
    { 
      QueueManager.AccountTransactionsQueue.AddMessage( 
        new CloudQueueMessage(msg)); 
      response.StatusForTransaction = TransactionStatus.Succeded; 
    } 
    catch(StorageClientException) 
    { 
      response.StatusForTransaction = TransactionStatus.Failed; 
      response.Message = 
        String.Format("Unable to insert message in the account transaction queue userId|AccountId={0}, messageId={1}", 
        accountTransaction.PartitionKey, accountTransaction.RowKey); 
    } 
  } 
  return response; 
}

A classe QueueManager irá inicializar filas usando definições da configuração:

CloudQueueClient queueClient = 
  CloudStorageAccount.FromConfigurationSetting(
    "DataConnectionString").CreateCloudQueueClient();
accountTransQueue = queueClient.GetQueueReference(
  Helpers.Queues.AccountTransactionsQueue);
accountTransQueue.CreateIfNotExist();

loggQueue = queueClient.GetQueueReference(
  Helpers.Queues.AccountTransactionLoggQueue);
loggQueue.CreateIfNotExist();

AccountStorageWorker escuta as mensagens no AccountTransactionQueue e obtém as mensagens da fila. Para poder ouvir a mensagem, o operador deve abrir a fila correta:

var storageAccount = CloudStorageAccount.FromConfigurationSetting(
  "DataConnectionString");
// initialize queue storage 
CloudQueueClient queueStorage = storageAccount.CreateCloudQueueClient();
accountTransactionQueue = queueStorage.GetQueueReference(
  Helpers.Queues.AccountTransactionsQueue);

Depois que a fila é aberta e AccountStorageWorker lê a mensagem, a mensagem será invisível na fila por 20 segundos (o tempo limite da visibilidade foi definido como 20). Durante esse tempo o trabalho tentará processar a mensagem.

Se processar a mensagem de êxito, a mensagem será excluída da fila. Se o processamento falhar, a mensagem será colocada novamente na fila.

Processamento de mensagens

O método ProcessMessage primeiro precisa obter o conteúdo da mensagem. Isso pode ser feito de duas maneiras. Primeiro, a mensagem pode ser armazenada como uma seqüência de caracteres na fila:

//userid|accountid|transactionid|amount
var str = msg.AsString.Split('|');...

Em segundo lugar, a mensagem ser serializados XML:

using (MemoryStream m = 
  new MemoryStream(msg.AsBytes)) {

  if (m != null) {
    XmlSerializer xs = new XmlSerializer(
      typeof(Core.TableStorage.UserAccountTransaction));
    var t = xs.Deserialize(m) as 
      Core.TableStorage.UserAccountTransaction;

    if (t != null) { ....... }
  }
}

Deve AccountStorageWorker por algum motivo estar desativado ou não é possível processar a mensagem, nenhuma mensagem serão perdida conforme ele é salvo na fila. Se processamento dentro do AccountStorageWorker deve falharem, a mensagem não será removida da fila e ele se tornará visível na fila depois de 20 segundos.

Para garantir que esse comportamento, a chamada ao método DeleteMessage da fila é feita somente após a conclusão do trabalho. Se AccountStorageWorker não terminou de processar a mensagem antes do tempo limite, a mensagem novamente ficará visível na fila para que outra instância do AccountStorageWorker pode tentar processá-la. Figura 10 funciona em uma mensagem que foi armazenada como uma seqüência de caracteres.

Figura 10 de tratamento de mensagens em fila

if (str.Length == 4){
  //userid|accountid|transactionid|amount
  UserAccountSqlAzureAction ds = new UserAccountSqlAzureAction(
    new Core.DataAccess.UserAccountDB("ConnStr"));
  try
  {
    Trace.WriteLine(String.Format("About to insert data to DB:{0}", str),      
      "Information");
    ds.UpdateUserAccountBalance(new Guid(str[0]), new Guid(str[1]), 
      double.Parse(str[3]));
    Trace.WriteLine(msg.AsString, "Information");
    accountTransactionLoggQueue.DeleteMessage(msg);
    Trace.WriteLine(String.Format("Deleted:{0}", str), "Information");
  }
  catch (Exception ex)
  {
    Trace.WriteLine(String.Format(
      "fail to insert:{0}", str, ex.Message), "Error");
  }
}

Recurso idempotente

Se um dos clientes do Woodgrove Bank envia uma solicitação para transferir dinheiro de uma conta para outra e a mensagem é perdida? Se o cliente reenviar a mensagem, é possível que duas ou mais solicitações de acessar os serviços e são tratada separadamente.

Um dos membros da equipe do Woodgrove Bank identificada imediatamente esse cenário como um padrão idempotente recurso requer. Esse padrão exige que as operações ou recursos são implementadas de forma que eles são seguros para repetir. Em suma, a solução do Woodgrove Bank deseja implementar requer que os clientes bem comportados que anexe uma identificação exclusiva a cada solicitação e garante que eles serão reenvie a mesma mensagem exata, incluindo a identificação exclusiva mesma no caso de uma nova tentativa. Ser capaz de lidar com isso, a identificação exclusiva é salva no armazenamento de tabela Windows Azure. Antes de processar todas as solicitações, é necessário verificar se uma mensagem com essa identificação já foi processada. Se tiver sido processada, será criada uma resposta correta, mas o processamento associado à solicitação de nova não ocorrerá.

Embora isso signifique importuná o armazenamento de dados central com consultas extras, foi considerado necessário. Resultará em alguns deterioração de desempenho, pois algumas consultas forem feitas para o armazenamento de dados central antes que qualquer outro processamento possa ocorrer. No entanto, que permite isso consumir mais tempo e outros recursos é uma opção razoável para atender aos requisitos do Woodgrove Bank.

A equipe do Woodgrove Bank atualizados os métodos ReliableInsertMoney e ReliableWithDrawMoney o IUserAccountAction e suas implementações, adicionando uma identificação de transação:

TransactionResponse ReliableInsertMoney(
  Guid userId, Guid accountId, Guid transactionId, 
  double amount, bool serializeToQueue);

TransactionResponse ReliableWithDrawMoney(
  Guid userId, Guid accountId, Guid transactionId, 
  double amount, bool serializeToQueue);

A tabela UserAccountTransaction (Windows Azure armazenamento) foi atualizada adicionando TransactionId como RowKey, de modo que cada inserção na tabela teria um ID exclusivo.

A responsabilidade para o envio de uma identificação de mensagem exclusiva para cada transação exclusiva é definida para o cliente:

WcfClient.Using(new AccountServiceClient(), client =>{ 
  using (new OperationContextScope(client.InnerChannel)) 
  { 
    OperationContext.Current.OutgoingMessageHeaders.MessageId = 
      messageId; 
    client.ReliableInsertMoney(new AccountTransactionRequest { 
      UserId = userId, AccountId = accountId, Amount = 1000 }); 
  } 
});

A classe auxiliar usada aqui pode ser encontrada em soamag.com/I32/0909-4.asp.

IUserAccountService definição foi deixada inalterado. A única alteração necessária implementar essa funcionalidade é ler a MessageId os cabeçalhos de mensagem de entrada, que foi enviada pelo cliente, e usá-lo no processamento em segundo plano (consulte do Figura 11).

Figura 11 de captura de identificações de mensagem

public TransactionResponse ReliableInsertMoney(
  AccountTransactionRequest accountTransactionrequest) {
  var messageId = 
    OperationContext.Current.IncomingMessageHeaders.MessageId;
  Guid messageGuid = Guid.Empty;
  if (messageId.TryGetGuid(out messageGuid))
    //last parameter (true) means that we want to serialize
    //message to the queue as XML (serializeAsXml=true)
    return UserAccountHandler.ReliableInsertMoney(
      accounttransactionRequest.UserId, 
      accounttransactionRequest.AccountId, messageId, 
      accounttransactionRequest.Amount, true);
  else 
    return new TransactionResponse { StatusForTransaction = 
      Core.Types.TransactionStatus.Failed, 
      Message = "MessageId invalid" };      
}

UserAccountAction atualizado agora receberá uma identificação de transação para cada operação idempotentes. Quando o serviço tenta concluir uma operação idempotentes, ele verificará se a transação existe no armazenamento de tabela. Se a transação existir, o serviço retornará a mensagem da transação que foi armazenada na tabela AccountTransactionLogg. O ID de transação serão salvas como RowKey na tabela de armazenamento UserAccountTransaction. Para localizar o usuário correto e conta, o serviço envia a chave de partição (userid|accountid). Se o ID de transação não for encontrado, a mensagem será colocada no AccountTransactionsQueue para processamento adicional:

public TransactionResponse ReliableHandleMoneyInQueueAsXml(
  UserAccountTransaction accountTransaction) {
  TransactionResponse response = this.CheckIfTransactionExists(
    accountTransaction.PartitionKey, accountTransaction.RowKey);
  if(response.StatusForTransaction == TransactionStatus.Proceed) {
    ...
  }
  return response;
}

O método CheckIfTransactionExists (veja a Figura 12 ) é usado para garantir que a transação não foi processada. Ele tentará encontrar a ID de transação para uma conta de usuário específica. Se o ID de transação for encontrado, o cliente receberá uma mensagem de resposta com os detalhes da transação já concluído.

Figura 12 de Verificando Status de transação e ID

private TransactionResponse CheckIfTransactionExists(
  string userIdAccountId, string transId) {

  TransactionResponse transactionResponse = 
    new Core.Models.TransactionResponse();

  var transaction = this.TransactionExists(userIdAccountId, transId);
  if (transaction != null) {
    transactionResponse.Message = 
      String.Format("messageId:{0}, Message={1}, ", 
      transaction.RowKey, transaction.Message);
    transactionResponse.StatusForTransaction = 
      TransactionStatus.Completed;
  }
  else
    transactionResponse.StatusForTransaction = 
      TransactionStatus.Proceed;
  return transactionResponse;
}

private UserAccountTransaction TransactionExists(
  string userIdAccountId, string transId) {
  UserAccountTransaction userAccountTransaction = null;
  using (var db = new UserAccountDataContext()) {
    try {
      userAccountTransaction = 
        db.UserAccountTransactionTable.Where(
        uac => uac.PartitionKey == userIdAccountId && 
        uac.RowKey == transId).FirstOrDefault();
      userAccountTransaction.Message = "Transaction Exists";
    }
    catch (DataServiceQueryException e) {
      HttpStatusCode s;
      if (TableStorageHelpers.EvaluateException(e, out s) && 
        s == HttpStatusCode.NotFound) {
        // this would mean the entity was not found
        userAccountTransaction = null;
      }
    }
  }
  return userAccountTransaction;
}

Uma propriedade interessante CheckIfTransactionExists é que se os dados que você deseja localizar não for encontrados, o Windows Azure Storage retorna um código de status HTTP 404 (porque ele usa uma interface REST). Além disso, se os dados não for encontrados, uma exceção será lançada pelos serviços de cliente do ADO.NET (System.Data.Services.Client).

Mais Info

Para obter mais informações sobre a implementação desta solução à prova de conceito, verifique o código de origem fornecido disponível on-line. SOA padrão descrições são publicadas em soapatterns.org . Para perguntas, entre em contato com herbjorn@wilhelmsen.se .

Arman Kurtagić é um consultor enfocando novas tecnologias da Microsoft, trabalhando em Omegapoint, que fornece direcionados aos negócios, soluções de TI seguras. Ele trabalhou em várias funções incluindo, desenvolvedor, arquiteto, mentor e empresário e tem experiência em setores como finanças, jogos e mídia.

Herbjörn Wilhelmsen é consultor trabalha para Forefront Consulting Group e é baseado em Estocolmo. Suas áreas de foco principal são service-oriented Architecture, arquitetura orientada a serviços e arquitetura comercial. Wilhelmsen é cadeira do Comitê de revisão de SOA padrões e também atualmente lidera o grupo de negócios TI de 2 no capítulo sueco do IASA. Ele é co-autoria do livro SOA com .NET e Azure* como parte do *Prentice Hall série computação orientada a serviços de Thomas Erl.

Thomas Erl* é autor SOA de vendidos no mundo, editor de seqüência da*Prentice Hall série computação orientada a serviços de Thomas Erle editor da SOA Magazine. Erl é o fundador da SOA Systems Inc. e o programa de SOA Certified Professional SOASchool.com. Erl é o fundador do manifesto da SOA grupo de trabalho e é dos alto-falantes e do instrutor para eventos públicos e privados. Para obter mais informações, visite thomaserl.com .

Graças ao especialista técnico seguir para revisar este artigo: Steve Marx