Commit b8362b9a authored by dwentzel's avatar dwentzel

added contracts and message types examples

parent 4f710b24
......@@ -14,6 +14,12 @@ This folder contains the source code for my [Service Broker Demystified blog ser
`GUIDs.sql` covers interesting aspects of SET NEW_BROKER vs ENABLE_BROKER.
`ServicesAndQueues.sql` demonstrates why we need to have both service and queue objects in Service Broker.
......
/*
This is the source code for http://www.davewentzel.com/content/service-broker-demystified-contracts-and-message-types.
Contracts and Message Types are optional in Service Broker. But they are helpful. Let's see why.
Let's build an EmployeeSvc and AccountingSvc. The goal is for the EmployeeSvc to submit an
ExpenseReport to the AccountingSvc.
*/
--basic setup
USE master
GO
CREATE DATABASE SBTest
GO
ALTER DATABASE SBTest SET NEW_BROKER
GO
USE SBTest
GO
/*
Here is the most basic configuration
*/
CREATE QUEUE AccountingQ;
--if we don't use [DEFAULT] then we've modeled a "send-only" service.
CREATE SERVICE AccountingSvc ON QUEUE AccountingQ ([DEFAULT]);
CREATE QUEUE EmployeeQ;
CREATE SERVICE EmployeeSvc ON QUEUE EmployeeQ;
--submit a rudimentary expense report
BEGIN TRANSACTION
DECLARE @h UNIQUEIDENTIFIER;
BEGIN DIALOG @h
FROM SERVICE [EmployeeSvc]
TO SERVICE 'AccountingSvc'
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @h;
COMMIT;
--let's ensure our message got to the AccountingQ
select convert(xml,message_body) AS message_body, service_contract_name,
message_type_name, validation
from AccountingQ
--this will not error either
BEGIN TRANSACTION
DECLARE @h1 UNIQUEIDENTIFIER;
BEGIN DIALOG @h1
FROM SERVICE [EmployeeSvc]
TO SERVICE 'AccountingSvc'
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @h1 ('This is my expense report');
COMMIT;
--let's ensure our message got to the AccountingQ
select convert(xml,message_body) AS message_body, service_contract_name,
message_type_name, validation
from AccountingQ
--Let's fix our design.
CREATE MESSAGE TYPE ExpenseReport VALIDATION = WELL_FORMED_XML;
--you'll see the format below...but we could also
--create an XML Schema here to be very precise with our constraint.
--the more precise the better.
--we also need a CONTRACT to limit who can send to whom using this message type
CREATE CONTRACT ExpenseSubmission (ExpenseReport SENT BY INITIATOR);
--we also need to modify the SERVICE to accept that contract instead of
--(or in addition to) [DEFAULT]
ALTER SERVICE AccountingSvc
(ADD CONTRACT ExpenseSubmission);
--let's test it out
BEGIN TRANSACTION
DECLARE @h2 UNIQUEIDENTIFIER;
BEGIN DIALOG @h2
FROM SERVICE [EmployeeSvc]
TO SERVICE 'AccountingSvc'
ON CONTRACT ExpenseSubmission --added this line
WITH ENCRYPTION = OFF;
--added some reasonable XML
SEND ON CONVERSATION @h2 MESSAGE TYPE ExpenseReport ('<ExpenseReport EmpId="123" ExpenseAmount="595.37" />');
COMMIT;
--and let's see if our new message, with better constraints, made it to the
--target service/queue...
--also note that our old messages are still available to be processed.
--Altering a service does not wipe out existing messages.
select convert(xml,message_body) AS message_body, service_contract_name,
message_type_name, validation
from AccountingQ
--with "constraints", this should fail
BEGIN TRANSACTION
DECLARE @h3 UNIQUEIDENTIFIER;
BEGIN DIALOG @h3
FROM SERVICE [EmployeeSvc]
TO SERVICE 'AccountingSvc'
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @h3 ('This is not XML, should fail.');
COMMIT;
--but our message made it to the queue because we didn't specify the ON CONTRACT
--clause.
select convert(xml,message_body) AS message_body, service_contract_name,
message_type_name, validation
from AccountingQ
--the problem is easily explainable. Although we bound a contract to our service
--we did not "unbind" the DEFAULT contract...so it is still valid. We can query the
--SSB metadata to prove this
select s.name AS ServiceName, sc.Name as ContractName
from sys.services s, sys.service_contract_usages u , sys.service_contracts sc
WHERE s.name = 'AccountingSvc'
AND s.service_id = u.service_id
AND u.service_contract_id = sc.service_contract_id
--let's drop the DEFAULT contract and try sending garbage again
ALTER SERVICE AccountingSvc
(DROP CONTRACT [DEFAULT]);
--let's try to send on the DEFAULT contract now.
--Note that we can (no error), but the message is "stuck" in the sending Q
BEGIN TRANSACTION
DECLARE @h4 UNIQUEIDENTIFIER;
BEGIN DIALOG @h4
FROM SERVICE [EmployeeSvc]
TO SERVICE 'AccountingSvc'
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @h4 ('Not XML...second try');
COMMIT;
select convert(xml,message_body) AS message_body, service_contract_name,
message_type_name, validation
from EmployeeQ
select convert(xml,message_body) AS message_body
from sys.transmission_queue
--basic cleanup
USE master;
GO
DROP DATABASE SBTest;
GO
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment