Message Addressing and Dispatching

Damir Dobric Posts

Next talks:

 

    

Follow me on Twitter: #ddobric



 

 

Archives

By implementing of the custom channel or by manipulating of the message in message inspectors (custom behaviors) it could often happen that the message is transferred from the client to the service, but it cannot be successfully posted to the destination service. I had very often this problem during implementation of custom channel. This is a reason why I decide to describe it in this post. Somebody who never implemented a custom channel and who never were digging in the world of message in an enterprise service buss, this all could sound as something unimportant and very specific. However, times are changing and services become more and more important. That means such problems in an interoperable environment will become soon a kind of "common staff".

To explain possible confusion Imagine, there is a client which invokes an operation at the service side. It means the client sends a message which could look as following one:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">daenet.file://localhost/cevapservice/custEndpoint</a:To> <a:Action s:mustUnderstand="1">cevapproduction/ICevap/ImaLiCevapa</a:Action>
</s:Header>
<s:Body>
 <ImaLiCevapa xmlns="cevapproduction">
  <cevapQuery xmlns:d4p1="http://schemas.datacontract.org/2004/07/Server"
             
xmlns:i=http://www.w3.org/2001/XMLSchema-instance>
   
<d4p1:Cijena>7</d4p1:Cijena>
   
<d4p1:KajmakYesNo>true</d4p1:KajmakYesNo>
  
</cevapQuery>
 
</ImaLiCevapa>
</s:Body>
</s:Envelope>

The message above corresponds to following contract and service:

[ServiceContract(Namespace="cevapproduction")]
public interface ICevap
{
 [OperationContract]
 string ImaLiCevapa(QueryData cevapQuery);
}

[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class CevapService : ICevap
{
  public string ImaLiCevapa(QueryData cevapQuery)
  {
   
return "cega ba?";
 
}
}

Addressing = None

In this post I would like to focus on message header. The sample message contains elements 'To' and 'Action'. These two elements are mandatory and describe the listening address of the service and the operation which will invoked during processing of this message (More about this can be found here: http://developers.de/blogs/damir_dobric/archive/2006/07/27/865.aspx ). The interesting at both of these two elements is the namespace attribute which specifies NONE-Addresing message: http://schemas.microsoft.com/ws/2005/05/addressing/none. When you see this in one message, the underlying binding is probably based on HTTP protocol (BasicHttpBinding) and messages are exchanged by using of Request/Reply pattern in one call. In such cases there is no need to correlate request and response message, because after receiving of the request, the service immediately retrieves the response.

Addressing != None

Now, let's build a custom binding based on HTTP protocol. The new binding should include this time message addressing:

CustomBinding custBinding = new CustomBinding();

TextMessageEncodingBindingElement txtElem = new TextMessageEncodingBindingElement();

txtElem.MessageVersion = MessageVersion.Soap11WSAddressing10;

custBinding.Elements.Add(txtElem);

HttpTransportBindingElement basicHttpBinding = new HttpTransportBindingElement();

custBinding.Elements.Add(basicHttpBinding);

basicHttpBinding.MaxReceivedMessageSize = 1000000000;

ChannelFactory<ICevap> customFactory = new ChannelFactory<ICevap>(custBinding, new EndpointAddress(new Uri("http://mylocalhost:8001/cevapservice/customEndpoint")));

transparentProxy = customFactory.CreateChannel();

transparentProxy.ImaLiCevapa(data);

By using of this binding the header of the message is slightly extended as shown in the next example:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
 
<s:Header>
  
<a:To s:mustUnderstand="1"
   xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">
         
daenet.file://localhost/cevapservice/custEndpoint</a:To
">
         
daenet.file://localhost/cevapservice/custEndpoint</a:To
   
<a:Action s:mustUnderstand="1">
   
cevapproduction/ICevap/ImaLiCevapa</a:Action
   
<a:MessageID>urn:uuid:25decce3-2dfa-4bad-8968-c4c047e89e04</a:MessageID>   
   <a:ReplyTo>
  
     <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>  

   </a:ReplyTo>
 
</s:Header>

 <
s:Body>
 
<ImaLiCevapa xmlns="cevapproduction">
   
<cevapQuery xmlns:d4p1="http://schemas.datacontract.org/2004/07/Server"
              xmlns:i
=http://www.w3.org/2001/XMLSchema-instance>
    
<d4p1:Cijena>7</d4p1:Cijena>
    
<d4p1:KajmakYesNo>true</d4p1:KajmakYesNo>
   
</cevapQuery>
 
</ImaLiCevapa>
 </s:Body>
</s:Envelope>

As you see, the new message has two new elements: MessageID and ReplyTo. By using of this encoding (addressing) the message can survive any message exchange pattern. For example, this message could live for years in some message queue. After processing the reply message can be correlated to the request message.

Internal dispatching of the message
The final destination of the message is determined by the invoking operation, corresponding service (logical host of operation) and the physical binding parameters.
For example, the service is hosted at the base address http://localhost:8001/cevapservice and relative address "httpEndpoint". Internally, the destination of the message is calculated as: http://localhost:8001/cevapservice/httpEndpoint.Following example shows how to start the host which listens at the named address:

Uri baseAddress1 = new Uri(http://localhost:8001/cevapservice);
ServiceHost host = new ServiceHost(typeof(CevapService), baseAddress1);
BasicHttpBinding httpBinding = new BasicHttpBinding
(BasicHttpSecurityMode.None);
host.AddServiceEndpoint(typeof(ICevap), httpBinding, "httpEndpoint");

#region Add Metadata
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri("http://localhost:8001/cevapservice/mex"); host.Description.Behaviors.Add(smb);
#endregion

host.Open();

Corresponding message header (none-addressing) which will be dispatched exactly to method ImaLiCevapa at the address http://localhost:8001/cevapservice/httpEndpoint looks as shown in the example bellow:

<a:To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">
daenet.file://localhost/cevapservice/custEndpoint</a:To>
<a:Action s:mustUnderstand="1">cevapproduction/ICevap/ImaLiCevapa</a:Action>

If one of specified parameters does not exactly match following error will occur at the service side while processing the message:

The message with To 'daenet.file://localhost/cevapservice' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree

This error is related to message which has following value in the message header To: 'daenet.file://localhost/cevapservice'.
However, the header has to contain the value: 'daenet.file://localhost/cevapservice/custEndpoint'.

Related link: http://developers.de/blogs/damir_dobric/archive/2006/08/06/907.aspx


Posted Apr 04 2007, 01:04 AM by Damir Dobric
Filed under:

Comments

Alen Siljak wrote re: Message Addressing and Dispatching
on 06-08-2008 6:37

hahaha, svaka cast na komentarima...

***

Great comments!

developers.de is a .Net Community Blog powered by daenet GmbH.