Este artigo foi traduzido por máquina.

Orientação de mensagens

Service Broker do SQL Server 2005: Nova tecnologia de mensagens Microsoft ’s

Juan Carlos (João Carlos) Olamendy Turruellas

No SQL Server 2005, a Microsoft introduziu a tecnologia de Service Broker (SSB), que suporta o padrão de design de agente e os princípios de middleware orientado para mensagens (MOM). Essa tecnologia, no entanto, foi pouco usada, apesar da capacidade do SSB, em contraste de uma abordagem de solicitação/resposta síncrona tradicional, para permitir que os desenvolvedores criar aplicativos de mensagens confiáveis, escalonáveis, distribuídos e assíncronos Implementando mecanismos enfileiramento de mensagens que são combinados com os recursos de banco de dados relacional do SQL Server.

Um agente é um componente de software que se situa entre aplicativos de empresa que exigem integração e interage com eles. Este middleware oculta a complexidade de protocolos de comunicação e topologias quando aplicativos precisam se conectar entre si para trocar dados. Ele também pode fornecer recursos como transformação e roteamento de mensagens, Gerenciando a execução da lógica de processo comercial dessa maneira.

Nesse modelo, funcionalidade é exposta como um serviço, e a troca de dados entre serviços é realizada por meio de mensagens independentemente dos aplicativos envolvidos on-line ao mesmo tempo. Esse modelo também permite que aplicativos compostos menos rígidos e garante que as mensagens não serão perdidas. Neste artigo, descreverei os principais conceitos do SSB por ilustrando um cenário de negócios do mundo real que mostra o potencial das soluções compostos baseados em mensagens.

Aplicativo do SSB em um cenário de Business reais

O contexto principal no qual você pode aplicar SSB tecnologia é no desenvolvimento de uma solução de integração de aplicativos empresariais. Esses aplicativos geralmente oferece suporte ao gerenciamento e automação de processos comerciais que exigem confiável middleware orientado a mensagens (nenhuma mensagem será perdida) para a troca de informações entre eles. Além disso, esses aplicativos residem em um ambiente complexo com um grande número de sistemas e usuários. Nem todos os aplicativos estão on-line ao mesmo tempo e seu processamento de solicitações de maneira menos rígida pode levar muito tempo.

Em um modelo de solicitação-resposta tradicional, comunicação entre os sistemas back-end é síncrona e a lógica do processo de negócios é implementada (usando uma linguagem de alto nível como translation from VPE for Csharp ou Java) por meio de componentes na camada de negócios da sua solução e como uma série de transações do banco de dados. Nesta abordagem, se um sistema back-end estiver inativo, todo o processo passa para um status de espera. Por exemplo, você não pode autorizar um cartão de crédito se o sistema de pagamento estiver inativo.

O objetivo principal dos aplicativos SSB é integrar sistemas da empresa por meio de um canal de comunicação comum. Alguns aplicativos externos (ERP, gerenciamento de cadeia de fornecimento, CRM e outros) ou módulos internos (código T-SQL e CLR gerenciado disparadores e procedimentos armazenados) colocados mensagens em filas, enquanto suas contrapartes recebem notificações de que as mensagens estão nas filas (e precise ser recuperados e será) por meio de um disparador ou uma operação SEND/RECEIVE regular. A visão aqui se baseia em um sistema corporativo cujos componentes do lado do servidor podem aceitar solicitações imediatamente mas adiar o processamento de solicitações, retornando uma mensagem informativa para o cliente indicando que ele deve aguardar a resposta mais tarde.

A solução de SSB assíncrona de exemplo ilustrada neste artigo (de consulte Figura 1) inclui um site de portal e estoque de armazenamento e bancos de dados. O site de portal tem duas páginas da Web: uma para inserir dados associados a uma solicitação de pedido e outro para exibir o status da ordem. O aplicativo de banco de dados de armazenamento recebe solicitações de ordem no site de portal, persiste dados em tbOrder tabela e envia dados de solicitação a ordem no formulário de mensagens em uma fila em um barramento comuns no canal de comunicação no qual o aplicativo de banco de dados de estoque escuta. Banco de dados de inventário recebe pedidos de solicitação de entrada e manipula a entrega de estoque e distribuição de depósito. Ele também cria uma resposta de ordem subjacente e o envia, usando outra fila ao banco de dados do armazenamento. Finalmente, o banco de dados de armazenamento verifica se há mensagens de resposta de ordem e atualiza o status da base ordem solicitação linha (OK ou status incorreto) em tbOrder a tabela, que permite aos usuários verificar o status de ordens. Dessa forma, a solução distribuída delega todos os procedimentos de mensagens, backup, administração e tolerância a falhas para a infra-estrutura SSB (aplicando o padrão de design de agente) e concentra-se o seu esforço no domínio do problema.


Figura 1 O cenário de comércio eletrônico, como uma composição solução de Enterprise Systems

Do ponto de vista dos princípios SSB, o aplicativo de banco de dados de armazenamento inicia uma conversação com o aplicativo de banco de dados de estoque, enviando uma mensagem de solicitação ordem para a fila do aplicativo de inventário através de interfaces públicas com base nos serviços. Os serviços são pontos de extremidade lógicos em tecnologias SSB, que usam filas como o repositório de mensagem e especifique sua funcionalidade usando contratos. Contratos de especificar a direção de mensagens e seu tipo de mensagem subjacente em uma determinada conversação. Depois que uma mensagem é colocada em fila (enfileirados), o aplicativo de armazenamento continua com outras tarefas. Quando o aplicativo de inventário está pronto (Isso pode ser à noite ou em outro tempo ocioso), um programa se serviço obtém a mensagem da fila e processos que ele e o aplicativo de banco de dados de estoque envia uma mensagem confirmando que a ordem foi processada juntamente com o resultado final. (Veja a Figura 2.)


Figura 2 A arquitetura da solução SSB

Como analisar a arquitetura da solução SSB, você pode reconhecer que a solução de integração subjacente pode ser realizada usando outras tecnologias de mensagens, como MSMQ e o Microsoft BizTalk Server. No entanto, Microsoft SQL Server juntamente com o Service Broker fornece uma infra-estrutura confiável no qual criar aplicativos compostos e tem um nível de capacidade de recuperação, manutenção, durabilidade, desempenho e escalabilidade que pode ser encontrada somente em um sistema de banco de dados. Os recursos de qualidade de serviço do SSB incluem o seguinte:

  • Transações. Se uma mensagem é retirada da fila e ocorre um erro, a mensagem não serão perdida.
  • Capacidade de recuperação. Se o sistema falhar devido a falhas de mídia, problemas o processador ou na memória principal ou o sistema é submetido a uma interrupção, a mensagem deve ser conduzida permanentemente para o sistema continuar o processamento quando ele é restaurado.
  • Escalabilidade. Depois que as mensagens são lançadas em uma fila, eles são processados com uma taxa que não apresenta problemas de desempenho quando mais recursos são adicionados. A carga de trabalho pode aumentar a milhares de mensagens por segundo, mas a carga de trabalho pode ser balanceada distribuindo o trabalho entre várias instâncias SSB participantes.

Implementação da solução

Nesta seção, eu orientam sobre como implementar a solução SSB para o cenário de negócios. Os bancos de dados principais são os bancos de estoque e armazenamento de dados, que são hospedados em servidores diferentes. Isso significa que você precisa estabelecer conexões com esses sistemas usando o SQL Server Management Studio.

A primeira etapa é habilitar recursos de Service Broker e segurança de transporte em ambos os bancos de dados (consulte Figura 3), configurando o nível de instâncias subjacente no catálogo do sistema (banco de dados mestre).

Figura 3 Ativar SSB e recursos de segurança de transporte em bancos de dados de participantes

--- Configure Instance1.
use master;
alter database Store set ENABLE_BROKER;
alter database Store set TRUSTWORTHY ON;
use Store;
create master key encryption by password = 'Store*-';

--- Configure Instance2.
use master;
alter database Inventory set ENABLE_BROKER;
alter database Inventory set TRUSTWORTHY ON;
use Inventory;
create master key encryption by password = 'Inventory*-';

Configurações de segurança

A próxima etapa é configurar a infra-estrutura de comunicação entre as duas instâncias do SQL Server e bancos de dados para estabelecer um canal seguro envolvendo autenticação e, opcionalmente, criptografia de mensagens. Você pode usar o Windows ou autenticação baseada em certificados.

Sob o mecanismo do Windows, cada instância do SQL Server faz logon em outro usando as credenciais das contas de usuário Windows sob a qual os processos estão sendo executados. Ele necessário que ambas as instâncias do SQL Server usar uma conta de usuário de domínio com privilégios para fazer logon como um serviço e enviar mensagens.

Sob o mecanismo de certificado, cada instância do SQL Server autentica o outro usando um certificado digital. No SQL Server 2005, necessário que você gerar um par de chave pública/particular como a primeira etapa para configurar uma infra-estrutura chave pública. A chave particular é protegida pela chave mestre de banco de dados do banco de dados mestre e é usada principalmente para estabelecer identidade ’s sistema por interchanging dados criptografados com a chave particular e verificado com a chave pública no outro lado. Em seguida, cada ponto de extremidade SSB está configurado para usar certificados gerados para autenticação e criptografia.

Estrutura de mensagem e validação

Em seguida, você precisa especificar os objetos de comunicação subjacentes, como esquemas XML, tipos de mensagens, fila, contratos e serviços, que são usados por esse canal protegido. Uma mensagem é o proprietário conteúdo dos dados transmitidos, e cada instância tem um tipo de mensagem associada. Para determinar a estrutura de mensagens interchanged, você pode usar tipos de mensagens para especificar a estrutura e restrições das instâncias de mensagem subjacente. Isso pode ser um objeto binário simples, um documento XML válido ou um documento XML bem formado. Usei padrões de XML para representar e formatar as mensagens de nossa solução de integração. Nesse cenário de negócios, a primeira mensagem representa a ordem enviadas do armazenamento de banco de dados para o banco de dados inventário usando um documento XML bem formado (descrito pelo esquema OrderRequestSchema e o tipo de mensagem OrderRequestMsgType e que contém dados sobre o identificador de ordem, identificador de cliente, data do pedido e o item solicitado com seu identificador, o preço e a quantidade). A segunda mensagem representa a resposta correlacionada enviada pelo banco de dados destino usando um documento XML bem formado, muito (descrito por tipo de mensagem OrderResponseMsgType OrderResponseSchema esquema e que contém dados sobre a solicitação de mensagem correlacionados, processar status e descrição). Figura 4 define os esquemas XML usados para especificar e validar a estrutura das mensagens de pedido solicitação e resposta de ordem.

Figura 4 O esquemas XML para ordem solicitação e resposta de pedido mensagens

--- Create the schemas.
create xml schema collection OrderRequestSchema as
N'
<xs:schema xmlns="http://www.mycorporation.com/2007_schemas/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.mycorporation.com/2007_schemas/" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="Order">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="LineItem">
                    <xs:complexType>
                        <xs:attribute name="ItemNumber"
                                      type="xs:int"/>
                        <xs:attribute name="Quantity"
                                      type="xs:int"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute name="Id" type="xs:int"/>
            <xs:attribute name="Customer" type="xs:int"/>
            <xs:attribute name="Order_date" type="xs:dateTime"/>
        </xs:complexType>
    </xs:element>
</xs:schema>
'
go


create xml schema collection OrderResponseSchema as
N'
<xs:schema xmlns="http://www.mycorporation.com/2007_schemas/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"
 targetNamespace="http://www.mycorporation.com/2007_schemas/" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="OrderConfirmation">
        <xs:complexType>
            <xs:sequence>
               <xs:element name="Id" type="xs:int"/>
                     <xs:element name="Processing_Status" type="xs:int"/>
                     <xs:element name="Processing_Description"
                       type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
'
Go

O código a seguir cria em ambos os sistemas os tipos de mensagens com base em esquemas anteriores, que fazem parte da interface do seus serviços SSB.

create message type OrderRequestMsgType validation= VALID_XML 
             with schema collection OrderRequestSchema;
 

create message type OrderResponseMsgType validation=VALID_XML 
             with schema collection OrderResponseSchema;
go

A cláusula WITH SCHEMA COLLECTION indica que o SSB tem que validar mensagens contra os esquemas XML definidos. SSB executa a validação, assim que o serviço de destino recebe as mensagens. Se o conteúdo doesn’t passar na validação, SSB retornará uma mensagem de erro. Ele ’s pena destacar que a mensagem de validação pode ser bastante cara. Portanto, recomendável que mensagem de validação esteja ativado para processar mensagens de fontes não confiáveis porque incorretas de mensagens podem ser descobertas desde o início;Caso contrário, esse recurso pode ser desativado. Você pode referir-se a SQL Server Books Online para compreender melhor sintaxe de criação do tipo de mensagem.

Definição de infra-estrutura de comunicação

Depois de criar os tipos de mensagens, você precisará definir os contratos em ambos os sistemas para especificar quais mensagens (e em qual direção) o serviço pode enviar ou receber. Um contrato também determina se uma mensagem é enviada pelo iniciador da conversação, pelo destino da conversação ou o iniciador ou o destino da conversação. Nesse caso, o iniciador é o banco de dados de armazenamento e o destino for o banco de dados de inventário. A cláusula SENT BY especifica pontos de extremidade envolvidos e sua função subjacente. SSB garante que somente os tipos de mensagem que são definidos em um contrato são tratados e processados. Se um serviço envia outro tipo de mensagem, a mensagem será rejeitada e uma mensagem de erro é enviada de volta.

create contract OrderProcessingContract
       (OrderRequestMsgType sent by initiator,OrderResponseMsgType sent by
         target)
go

Você também precisará criar uma tabela denominada tbOrder no banco de dados armazenamento para registrar os dados na solicitação de ordem junto com seu status de processamento e a descrição (retornado do banco de dados Inventário) para que o cliente pode verificar a ordem usando uma página da Web. Código a seguir mostra como criar a tabela. O campo OrderStatus na tabela a pode ter um dos três valores:

  • Valor = 0. Ordem de processamento não;o campo OrderStatusDescription é nulo.
  • Valor = 1. Ordem de processamento sem erros;o campo OrderStatusDescription é nulo.
  • Valor = 2. Ordem de processamento com erros;obter mais detalhes no campo OrderStatusDescription.
create table tbOrder
(
   nOrderID int identity(1,1) primary key,
   nCustomer int,
   dtOrderDate datetime,
   nItemNumber int,
   nItemQuantity int,
   nOrderStatus int,
   vcOrderStatusDescription varchar(50)
);

Para inserir os dados de ordem que são inseridos no front-end portal da Web em tbOrder tabela, você pode definir um procedimento armazenado, mostrado no Figura 5 como a principal interface para enviar os dados subjacentes e retornar um número de ordem. O número da ordem é exibido em algum outro ponto no tempo e usado pelo usuário para solicitar o status da ordem subjacente.

Figura 5 Criando o procedimento armazenado spInsertOrder

create procedure spInsertOrder
  @nOrderID int output,
  @nCustomer int,
  @dtOrderDate datetime,
  @nItemNumber int,
  @nItemQuantity int
as
begin
  insert into tbOrder(nCustomer, dtOrderDate, nItemNumber, nItemQuantity,
    nOrderStatus)
  values(@nCustomer, @dtOrderDate, @nItemNumber, @nItemQuantity, 0);
  set @nOrderID=@@IDENTITY;
end;

A próxima etapa é criar filas para armazenar as mensagens recebidas (ou do serviço de destino ou do servidor iniciador) que devem ser processadas. Quando SSB recebe e valida uma mensagem (como explicado anteriormente), ele insere a mensagem na fila. (Você pode consulte nos manuais online do SQL Server para obter documentação da instrução CREATE QUEUE.)

Uma fila pode ser vinculada a um procedimento armazenado que manipula automaticamente as mensagens (sempre que um é enviado para a fila) e as processa. Um parâmetro importante na criação da fila é MAX_QUEUE_READERS, que especifica o número máximo de instâncias do procedimento armazenado da ativação que inicia a fila ao mesmo tempo. O valor de MAX_QUEUE_READERS deve ser um número entre 0 e 32.767. Se você esperando ordem solicitações a uma taxa mais rápida que um leitor pode processá-los, você pode especificar vários leitores de fila para instanciar mais leitores conforme necessário até que o número máximo é atingido. Ele ’s a pena observar que esse procedimento deve ser criado antes da fila, mas para fins de neste artigo, a lógica de negócios desse procedimento é discutida na seção “ uma conversação entre serviços no SSB Technology. ” No exemplo, estamos a fila de leitura e processando as mensagens automaticamente, mas alguns cenários de negócios exigem a intervenção de usuários, que significa que a fila deve ser lido por usando a lógica subjacente exposta como um procedimento armazenado a ser chamado de uma interface gráfica do usuário.

Até este ponto, criou para os dois sistemas os objetos de banco de dados que estabelecem o canal de comunicação bidirecional e seu entendimento comum. Em seguida, você precisará criar artefatos para cada sistema que fornecem a funcionalidade de processamento de ordem.

Primeiro você precisará criar uma fila no banco de armazenamento de dados (o spStoreDB_QueueReader subjacente do procedimento armazenado deve ser criada pela primeira vez;consulte Figura 8) para armazenar e processar mensagens de ordem de resposta de entrada e atualizar o status de ordem no tbOrder tabela.

--- Create the queue on the Store database
create queue StoreQueue with status=on,
  activation (procedure_name=spStoreDB_QueueReader,max_queue_readers=5,
  execute as 'dbo');
go

Depois crie outra fila no banco de dados inventário (o spStoreDB_QueueReader subjacente do procedimento armazenado deve ser criada pela primeira vez;consulte Figura 7) para receber ordem mensagens de solicitação do armazenamento de banco de dados e processá-los.

--- In the Inventory database
create queue InventoryQueue with status=on,
  activation (procedure_name=spInventoryDB_QueueReader,max_queue_readers=5,
  execute as 'dbo');
go

Agora você precisa definir serviços, mostrados no código a seguir. Um serviço representa um ponto de extremidade em nível de aplicativo na solução SSB e pode ser o iniciador e o destino das mensagens. Um serviço pode ser vinculado a várias combinações de fila e contrato. SSB pode ativar um serviço automaticamente sempre que uma nova mensagem chega em uma fila e SSB também pode agendar um evento para a ativação ou executar o serviço manualmente. Os serviços do SSB são criados independentemente em ambos os sistemas de banco de dados.

--- In the Store database
create service StoreService on
       queue StoreQueue(OrderProcessingContract);
go

--- In the Inventory database
create service InventoryService on
       queue InventoryQueue(OrderProcessingContract);
go

E você também precisa criar uma rota na qual deseja transmitir mensagens do serviço para o ponto de extremidade remoto. As rotas são os canais de comunicação encaderná os serviços.

--- Create route to InventoryService from Store database
create route Route2Inventory
     with service_name = 'InventoryService',
          address = 'tcp://Instance2:4037';

--- Create route to StoreService from Inventory database
create route Route2Store
     with service_name = 'StoreService',
          address = 'tcp://Instance1:4037';

Neste ponto, você ’re pronto para criar uma ligação de serviço remoto que mapeia as credenciais que são usadas para abrir uma conversação com um ponto de extremidade remoto SSB. ’S aqui o código para as ligações.

--- Create remote service binding on Store database
create remote service binding ToInventory_RSB
     to service 'InventoryService'
     with user = InventoryUser;


--- Create remote service binding on Inventory database
create remote service binding ToStore_RSB
     to service 'StoreService'
     with user = StoreUser;

Uma conversa entre serviços no SSB Technology

Para estabelecer um canal de comunicação entre os serviços em SSB, tudo o que você precisa fazer é começar uma conversa. Esta conversa é criada usando a instrução BEGIN CONVERSATION DIALOG, e cada instância tem um identificador exclusivo que representa o canal para trocas de dados. Você pode usar a instrução SEND para transmitir mensagens através de conversas abertas específicas, definindo o tipo de mensagem e seu conteúdo. Finalmente, para concluir uma conversação, a instrução END CONVERSATION é usada.

Figura 6 mostra um procedimento armazenado chamado pelo usuário que irá inserir os dados de solicitação de ordem, registre essa informação em tbOrder tabela, iniciar uma conversa transacional entre o banco de dados de armazenamento e o banco de dados inventário através do contrato e do serviço criado anteriormente e enviar uma instância do documento de solicitação de pedido do esquema XML OrderRequestSchema nesta conversa. Esse procedimento é chamado pelo usuário através da página de entrada de dados de solicitação de pedido no portal da Web.

Figura 6 EnterOrderRequest O procedimento armazenado no banco de dados de armazenamento

--- Create the stored procedure EnterOrderRequest on the Store database
create procedure spEnterOrderRequest
  @nOrderID int output,
  @nCustomer int,
  @nItemNumber int,
  @nItemQuantity int
as
begin
  declare @dialog_handle uniqueidentifier;
  declare @Order_XDoc xml(OrderRequestSchema);
  declare @dtNow datetime;
  
  set @dtNow = getdate();
  begin transaction
     exec spInsertOrder @nOrderID 
output,@nCustomer,@dtNow,@nItemNumber,@nItemQuantity;

     set @Order_XDoc =
       '<Order xmlns="http://www.mycorporation.com/2007_schemas/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.mycorporation.com/2007_schemas/" 
          Id="'+cast(@nOrderID as varchar(10))+
              '" Customer="'+cast(@nCustomer as varchar(10))+'" 
              Order_date="'+convert(varchar,@dtNow,126)+'-05:00">
          <LineItem ItemNumber="'+cast(@nItemNumber as varchar(10))+
              '" Quantity="'+cast(@nItemQuantity as varchar(10))+'"/>
       </Order>';


     begin dialog conversation @dialog_handle
     from service StoreService
     to service 'InventoryService'
     on contract OrderProcessingContract;


     send on conversation @dialog_handle 
     message type OrderRequestMsgType(@Order_XDoc);
  commit;
end;

Você pode verificar o status da transmissão de executar uma consulta, como a seguir no sys.transmission_queue de tabela de sistema e observando transmission_status o campo no conjunto para descobrir mensagens de erro de resultados.

---- Check the transmission status on the Store database.
select *
from sys.transmission_queue;

Agora você também pode examinar a mensagem que chega na fila de destinatário (no caso da fila InventoryQueue) usando a instrução SELECT sobre a fila subjacente e analisar o conjunto de resultados.

select message_type_name, cast(message_body as xml) message, queuing_order,
       conversation_handle, conversation_group_id
from InventoryQueue;

Em seguida, você precisará processar a mensagem de solicitação de ordem de entrada e enviar uma resposta do pedido no banco de dados armazenamento com o status de processamento real. Primeiro criamos o procedimento armazenado que implementa a lógica do leitor de fila associado à fila InventoryQueue. Para começar, você precisa receber a mensagem de solicitação de ordem da fila de inventário usando a instrução RECEIVE TOP (1). Você recuperar o identificador de ordem e item usando o método de valor XQuery de tipos de dados XML e, em seguida, verificar se o produto existe no banco de teste de dados AdventureWorks na tabela Production.Product. Em seguida você criar a mensagem de resposta ordem com o status adequado processamento e a descrição, enviar esta mensagem por meio da caixa de diálogo conversação aberta usando a instrução SEND ON CONVERSATION e finalmente finalizar a conversação usando a instrução END CONVERSATION. O código é mostrado na Figura 7.

A instrução RECEIVE é semelhante a instrução SQL SELECT em que você possa consultar um objeto de banco de dados (nesse caso uma fila) e atribui os valores de resultado a variáveis. A instrução RECEIVE exclui as mensagens da fila após recebê-los, ao contrário da instrução SELECT, não exclui os registros das tabelas. XQuery é a linguagem de consulta emergentes para fontes de dados XML. Ele usa expressões XPath para endereçar partes específicas de documentos. Por exemplo, a expressão (/ ns:Order/@Id)[1] lhe permite selecionar o filho de ID de atributo do primeiro elemento ordem no documento XML transmitido. Embora o XQuery foi criado principalmente como uma linguagem de consulta, agora ele aprimorado para fornecer recursos de transformação, como XSLT.

Figura 7 criando spInventoryDB_QueueReader Stored Procedure para ler mensagens da fila InventoryQueue

--- Create stored procedure to process the incoming order request message
create procedure spInventoryDB_QueueReader
as
begin
  declare @Conv_Dialog_Handle uniqueidentifier;
  declare @Conv_Group_Handle uniqueidentifier;
  declare @Order_XDoc xml(OrderRequestSchema);
  declare @OrderConfirmation_Text varchar(8000);
  declare @OrderConfirmation_XDoc xml(OrderResponseSchema);
  declare @nOrderId int;
  declare @nItemNumber int;
  declare @nItemQuantity int;
  declare @nItemNumberResult int;
  declare @nProcessing_Status int;
  declare @vcProcessing_Description varchar(120);


  begin transaction;
    --- Receive the message from the queue
    receive top(1) @Order_XDoc = message_body,
                   @Conv_Dialog_Handle = conversation_handle,
                   @Conv_Group_Handle = conversation_group_id
    from InventoryQueue;


    --- Retrieve the order identifier
    select @nOrderId = @Order_XDoc.value
('declare namespace ns="http://www.mycorporation.com/2007_schemas/";(/ns:Order/@Id)[1]', 'int');
    select @nItemNumber = @Order_XDoc.value
('declare namespace ns="http://www.mycorporation.com/2007_schemas/";
(/ns:Order/ns:LineItem/@ItemNumber)[1]', 'int');
   

    --- Process the incoming order request
    select @nItemNumberResult=ProductID
    from AdventureWorks.Production.Product
    where ProductID=@nItemNumber;


    if (@nItemNumberResult is null)
    begin
       set @nProcessing_Status = 2;
       set @vcProcessing_Description = 'Processing transaction not
                                       'successfully. No product in the
                                       'Inventory database';
    end
    else
    begin
       set @nProcessing_Status = 1;
       set @vcProcessing_Description = 'Processing transaction successfully.
                                       'Found product in the Inventory 
                                       'database';
    end;


    --- Create the Order Confirmation message as a response
    set @OrderConfirmation_Text = 
            '<OrderConfirmation xmlns="http://www.mycorporation.com/2007_schemas/"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.mycorporation.com/2007_schemas/">
                <Id>'+cast(@nOrderId as varchar(10))+'</Id>
                <Processing_Status>'+cast(@nProcessing_Status as varchar(10))+'</Processing_Status>
                <Processing_Description>'+@vcProcessing_Description+'</Processing_Description>
            </OrderConfirmation>';


    set @OrderConfirmation_XDoc = @OrderConfirmation_Text;


    ---- Send the message through the open conversation dialog (@Dialog_Handler)
    send on conversation @Conv_Dialog_Handle
    message type OrderResponseMsgType(@OrderConfirmation_XDoc);


    ---- End the conversation
    end conversation @Conv_Dialog_Handle;
  commit;
end;
go

No banco de dados de armazenamento, você pode verificar a resposta de confirmação para a solicitação de pedido com o código a seguir.

---- Check the messages on the StoreQueue on the Store database.
select message_type_name, cast(message_body as xml) message, queuing_order,
       conversation_handle, conversation_group_id
from StoreQueue;

Agora criamos spStoreDB_QueueReader o procedimento armazenado, que implementa a lógica do leitor de fila associado à fila StoreQueue. Ele usa a mesma lógica como spInventoryDB_QueueReader para obter as mensagens do StoreQueue e atualizar tbOrder tabela com o status de processamento e a descrição. O código é mostrado no Figura 8.

Figura 8 Criar spStoreDB_QueueReader Stored Procedure para ler mensagens da fila StoreQueue.

--- Create stored procedure to process the order response message
create procedure spStoreDB_QueueReader
as
begin
  declare @Conv_Dialog_Handle uniqueidentifier;
  declare @Conv_Group_Handle uniqueidentifier;
  declare @Order_XDoc xml(OrderResponseSchema);
  declare @nOrderId int;
  declare @nProcessing_Status int;
  declare @vcProcessing_Description varchar(50);


  begin transaction;
    --- Receive the message from the queue
    receive top(1) @Order_XDoc = message_body,
                   @Conv_Dialog_Handle = conversation_handle,
                   @Conv_Group_Handle = conversation_group_id
    from StoreQueue;


    --- Retrieve the order identifier
    select @nOrderId = @Order_XDoc.value('declare namespace 
ns="http://www.mycorporation.com/2007_schemas/";(/ns:OrderConfirmation/ns:Id)[1]', 'int');
    select @nProcessing_Status = @Order_XDoc.value('declare namespace 
ns="http://www.mycorporation.com/2007_schemas/";(/ns:OrderConfirmation/ns:Processing_Status)[1]', 'int');
    select @vcProcessing_Description = @Order_XDoc.value('declare namespace 
ns="http://www.mycorporation.com/2007_schemas/";
(/ns:OrderConfirmation/ns:Processing_Description)[1]', 'varchar(50)');
   

    update tbOrder
    set nOrderStatus=@nProcessing_Status,
      vcOrderStatusDescription=@vcProcessing_Description
    where nOrderID=@nOrderId;
  commit;
end;
go

Finalmente, você precisa implementar os componentes do site de portal, o front-end de nossa solução. O site de portal tem duas páginas, a página de entrada de solicitação de pedido e página de status do pedido. A página de entrada de solicitação de pedido permite aos usuários inserir os dados para a solicitação de pedido e chamar o procedimento armazenado spEnterOrderRequest, que implementa a lógica de negócios principal associada à ordem de processamento usando o direcionamento de Service Broker explicado anteriormente. O identificador de ordem será exibido para verificar o status da ordem mais tarde. A página de status de ordem permite que os usuários verifiquem o status da ordem inserindo o identificador de ordem.

Utilizei o Visual Studio para criar um novo site e adicionados dois formulários da Web. O primeiro, OrderRequest_EntryPage.aspx, contém três rótulos para descrever os campos para inserir, três controles de web TextBox (m_tbItemQuantity m_tbItemNumber, m_tbCustomerID) para obter dados sobre a solicitação de pedido e um botão de controle da web (m_btSubmit) que permite a execução da lógica de negócios de nossa solução e a exibição do identificador de ordem no rótulo de saída (m_lbOutput). Figura 9 mostra o código para a página. O code-behind associado OrderRequest_EntryPage.aspx é mostrado na Figura 10.

Figura 9 O Layout de OrderRequest_EntryPage.aspx.

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="OrderRequest_EntryPage.aspx.cs" Inherits="OrderRequest_EntryPage" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Order Request Entry page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <table border="0" width="100%" cellpadding="0" cellspacing="0">
          <tr>
            <td style="width:25%">
                <asp:Label ID="Label1" runat="server" Text="Enter
                  CustomerID"></asp:Label>            
            </td>
            <td style="width:75%">
                <asp:TextBox ID="m_tbCustomerID"
                  runat="server"></asp:TextBox>
            </td>
          </tr>  
          <tr>
            <td style="width:25%">
                <asp:Label ID="Label2" runat="server" Text="Enter Item
                  Number"></asp:Label>            
            </td>
            <td style="width:75%">
                <asp:TextBox ID="m_tbItemNumber" 
                  runat="server"></asp:TextBox>
            </td>
          </tr>
          <tr>
            <td style="width:25%">
                <asp:Label ID="Label3" runat="server" Text="Enter Item
                  Quantity"></asp:Label>
            </td>
            <td style="width:75%">
                <asp:TextBox ID="m_tbItemQuantity"
                  runat="server"></asp:TextBox>            
            </td>
          </tr>
          <tr>
            <td style="width:25%">
                <asp:Button ID="m_btSubmit" runat="server" Text="Submit" />
            </td>
            <td style="width:75%">
            </td>
          </tr>
          <tr>
            <td style="width:25%">
                <asp:Label ID="m_lbOutput" runat="server"
                  Text=""></asp:Label>
            </td>
            <td style="width:75%">
            </td>
          </tr>                              
        </table>
    </div>
    </form>
</body>
</html>

Figura 10 Atrás do código para a página OrderRequest_EntryPage.aspx.

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;


public partial class OrderRequest_EntryPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void m_btSubmit_Click(object sender, EventArgs e)
    {
        using (SqlConnection objConnection = new SqlConnection())
        {
            objConnection.ConnectionString = "Data Source=localhost;Initial
              Catalog=ServiceBrokerDB_Test;Integrated Security=True";
            using (SqlCommand objCmd = new SqlCommand())
            {
                objCmd.Connection = objConnection;
                objCmd.CommandType = CommandType.StoredProcedure;
                objCmd.CommandText = "spEnterOrderRequest";

                SqlParameter objOutputParam = 
                  objCmd.Parameters.Add("@nOrderID",SqlDbType.Int);
                objOutputParam.Direction = ParameterDirection.Output;
                objCmd.Parameters.Add("@nCustomer",SqlDbType.Int).Value = 
                  Convert.ToInt32(this.m_tbCustomerID.Text) ;
                objCmd.Parameters.Add("@nItemNumber", SqlDbType.Int).Value = 
                  Convert.ToInt32(this.m_tbItemNumber.Text);
                objCmd.Parameters.Add("@nItemQuantity", SqlDbType.Int).Value
                  = Convert.ToInt32(this.m_tbItemQuantity.Text);


                try
                {
                    objConnection.Open();
                    objCmd.ExecuteNonQuery();

                    this.m_lbOutput.Text = "The Order Identifier is " + 
                      objOutputParam.Value;
                }
                catch (SqlException ex)
                {
                    this.m_lbOutput.Text = "Exception: " + ex.Message;
                }
                finally
                {
                    objConnection.Close();
                }
            }
        }
    }
}

Em seguida é a implementação de OrderStatus_Page.aspx, que contém um controle de web de rótulo (Label1) e um web controle TextBox (m_tbOrderID) para obter o identificador de ordem e um controle de web de botão (m_btSubmit) que permite solicitando o status da ordem. O status é exibido usando uma última saída da web Label (m_lbOutput). O código para a página é mostrado no Figura 11, e o código por trás de Figura 12.

Figura 11 Layout de OrderStatus_Page.aspx.

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="OrderStatus_Page.aspx.cs" Inherits="OrderStatus_Page" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Order Status page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <table border="0" width="100%" cellpadding="0" cellspacing="0">
          <tr>
            <td style="width:25%">
                <asp:Label ID="Label1" runat="server" Text="Enter
                  OrderID"></asp:Label>            
            </td>
            <td style="width:75%">
                <asp:TextBox ID="m_tbOrderID" runat="server"></asp:TextBox>
            </td>
          </tr>
          <tr>
            <td style="width:25%">
                <asp:Button ID="m_btSubmit" runat="server" Text="Submit" 
                  OnClick="m_btSubmit_Click" />
            </td>
            <td style="width:75%">
            </td>
          </tr>          
          <tr>
            <td style="width:25%">
                <asp:Label ID="m_lbOutput" runat="server" 
                  Text=""></asp:Label>
            </td>
            <td style="width:75%">
            </td>
          </tr>                                       
        </table>    
    </div>
    </form>
</body>
</html>

Figura 12 Atrás do código para a página de OrderStatus_Page.aspx

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;


public partial class OrderStatus_Page : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {


    }
    protected void m_btSubmit_Click(object sender, EventArgs e)
    {
        using (SqlConnection objConnection = new SqlConnection())
        {
            objConnection.ConnectionString = "Data Source=localhost;
Initial Catalog=ServiceBrokerDB_Test;Integrated Security=True";
            using (SqlCommand objCmd = new SqlCommand())
            {
                objCmd.Connection = objConnection;
                objCmd.CommandType = CommandType.Text;
                objCmd.CommandText = "select vcOrderStatusDescription " +
                                     "from tbOrder " +
                                     "where nOrderID=@nOrderID";


                objCmd.Parameters.Add
("@nOrderID", SqlDbType.Int).Value = Convert.ToInt32(this.m_tbOrderID.Text);
                try
                {
                    objConnection.Open();
                    SqlDataReader objReader = objCmd.ExecuteReader();
                    objReader.Read();
                    string strStatusDescription = objReader.GetString(0);


                    this.m_lbOutput.Text = "The Order Status is " + strStatusDescription;
                }
                catch (SqlException ex)
                {
                    this.m_lbOutput.Text = "Exception: " + ex.Message;
                }
                finally
                {
                    objConnection.Close();
                }
            }
        }
    }
}

Com o exemplo que ’ve descrito, agora você tem um modelo para criar mensagens soluções usando tecnologias do SQL Server 2005 Service Broker, distribuído, confiável. Você deve ser capaz e adaptar exemplo ’s neste artigo para ajustar seu cenário de negócios.

Juan Carlos Olamendy Turruellas e um arquiteto de soluções de integração sênior e consultor. Seu foco principal é análise orientada a objeto e design, design de banco de dados, integração de aplicativos empresariais, Unified Modeling Language, padrões de design, arquitetura de aplicativo empresarial e processos de desenvolvimento de software usando metodologias ágeis.  Ele foi concedido status Most Valuable Professional pela Microsoft em 2007, 2008 e 2009, bem como status Oracle ACE em 2008.Você pode contatar Juan no de johnx_olam@fastmail.fm.