Contracts and Message Types have defaults, but the default is not [DEFAULT]. This leads to confusion to folks new to Service Broker. In this post I'll clear up the confusion and give you some tricks to keep things clear.
People tell me all the time that they don't want to use Service Broker because it is too confusing. I started a blog series called Service Broker Demystified to dispel these misconceptions. Today we are going to cover the [DEFAULT] objects, which are not really default objects...sometimes.
Quick review...a contract binds a message type (defined as the name of a message and how it is validated) to who may send it during a dialog. A service is defined as a set of tasks associated to a queue with a defined contract. Looking at the syntax of each SSB object might make it easier to comprehend.
Message types and contracts are always optional SSB objects...we'll cover why that is in the next post. But you should also note in the syntax above that the word DEFAULT is placed in square brackets. That is because DEFAULT not a keyword in SSB, it is the actual name of objects that are, by default (...couldn't resist), shipped by Microsoft.
I ran the follow queries on a database without SSB enabled. Here is the repro code if you want to try for yourself:
So, the syntax for CREATE MESSAGE TYPE and CONTRACT indicates that there are message types and contracts named DEFAULT...and we confirmed that by querying the SSB metadata.
But what is the DEFAULT...what does it mean?
- The DEFAULT message type, as you can see in the screenshot above means there is no validation done. By the way, this actually *is* the default behavior for a message type that did not specify the optional VALIDATION clause (see the screenshot above).
- The DEFAULT contract uses the DEFAULT message type (meaning there is no validation done). However, in this usage the [DEFAULT] object is not the default and MUST BE SPECIFIED to actually be used. If you don't believe me just look at the syntax again. Optional syntax is in square brackets and the message_type_name clause is NOT in square brackets.
Let me repeat, the fact that these objects are named DEFAULT is a misnomer...they are not actually the defaults. This leads to confusion and errors for the uninitiated. Let's create the simplest possible SSB solution to illustrate this fact...a simple employee expense submission. Here's the code to follow along:
Here we avoid all of this DEFAULT confusion by simply not using contracts and message types...they are optional anyway (see next post). We create two services and queues...the EmployeeSvc will enqueue a message to the AccountingSvc. DEFAULT is nowhere to be found in the code. On Line 33 we start the code to send a message. Note on Line 38 that we turn off encryption to avoid that headache (see the last post). Note that the message has no payload (Line 40).
This seems to me that it should work. But it doesn't.
The actual transmission error is "Service Broker received an error message on this conversation. Service Broker will not transmit the message; it will be held until the application ends the conversation." The message is "stuck" in the sending Q (EmployeeQ). The error embedded in the XML is "Target service 'AccountingSvc' does not support contract 'DEFAULT'.".
So, there you have it...we did not specify the [DEFAULT] contract, therefore we cannot use the [DEFAULT] contract and it generates an error. If you haven't fallen asleep yet you are probably thinking back to the syntax for the
CREATE SERVICE command (screenshot to the right). The "contract clause" is indeed listed as optional...and we were able to create the AccountingSvc without it...so what is going on?
When you create a service and do not specify the "contract clause" then the resultant service is a "send only" service. It cannot receive messages. This is because a sending service (or any service really) may potentially send to many different services each with its own contracts and message types. So we can't really restrict a sending service at all. All validation occurs on the receiving service. So when we created our two services we really created two sending services. SQL Server assumes we knew what we were doing.
So, the next question you probably have is how do we get our SSB design fixed and working as desired. All we really need to do is, minimally, declare that the [DEFAULT] contract should be used for the AccountingSvc, thus making it a target, with the [DEFAULT] validation, which is validation NONE. Let's see if that works. You can download the code to try it yourself:
It does work. So merely adding ([DEFAULT]) was enough to allow the Svc to receive messages.
Of course this isn't the most ideal setup since [DEFAULT] implies that there is NO VALIDATION. This means we can send just about anything and AccountingSvc will accept it.
The first message is the "no payload" message. The second is some meaningless text.
So the takeaway is that the [DEFAULT] contract is not really the default contract for a service. You must still declare it. If you don't then you created a send-only service. In the next post we'll cover why contracts and message types are optional, which builds on the concepts from this post.
You have just read "Service Broker Demystified - [DEFAULT] is not the DEFAULT" on davewentzel.com. If you found this useful please feel free to subscribe to the RSS feed.
sql server service broker service broker demystified