BizTalk Utilities CV ,   Jobs ,   Code library
 
Go to the front page to continue learning about XML or select below:

Contents

ReBlogger Contents

Previous posts in WSE

 
 
Page 20037 of 20217

Transports, channels, and the office mailroom

Blogger : Brain.Save()
All posts : All posts by Brain.Save()
Category : WSE
Blogged date : 2004 May 25

I work in a fairly large office building with a central mailroom. The existence of this mailroom greatly simplifies life for both me and the postal service employee who delivers mail to my building. I have a centralized place to pick up my mail, and the mail carrier doesn’t have to hunt around the entire building looking for every individual office. Instead, there’s one guy at my company whose job is to take the bundle of incoming mail and distribute it to the mailboxes of each person in the building. In this way, large numbers of messages can be delivered to their appropriate recipients quickly, with minimal work on everyone’s part.

There’s an analogy between an office mailroom and the messaging internals of WSE2. Both systems, in effect, solve similar problems, and by looking at how one functions it is possible to understand the other.

My office building houses many message destinations (people) within a single physical address. The WSE2 analogy of my office building is an application that hosts a set of services. Although this application might host a large number of services, it only needs one transport address. For example, many different services can be hosted over the same TCP port. One address – many destinations. This is a new notion in WSE2, made possible by WS-Addressing. In ASMX web services, the concept of “service identity” and “transport address” are bound up into a single URI. In other words, the problem of logically identifying a service is inextricably linked with the problem of delivering messages to it. In WSE2, services have an “identity URI” which uniquely identifies the service for things like policy application as well as a “transport address”, which tells the infrastructure how to get messages from point A to point B. Keeping these two ideas separate is important when you start thinking about exposing a service over a variety of network transports. WSE addresses this separation through the EndpointReference.Via property – the details of which can be found over on Hervey’s blog. For the purposes of this analogy, though, it’s sufficient to say that many services can be hosted on the same transport address in the same way that many people can have mail delivered to the same office building.

By the time a letter arrives at my office building, it’s already traveled through a complicated infrastructure in order to get from its original sender to my building. From the perspective of my office mail clerk, though, this process “just happens” and he doesn’t have to be concerned about its internals. All the mail clerk has to do is be familiar enough with the protocols of the network to transfer messages on and off of it – in the real world, this means signing USPS delivery confirmations and filling out shipping labels. In the WSE2 analogy, the infrastructure for exchanging messages with the outside world is implemented using some sort of standardized message exchange technology (e.g. TCP, UDP, SMTP, HTTP, MSMQ, etc). The WSE 2.0 “mail clerk” must implement enough of the network protocols to move messages on and off of the underlying network.

In WSE2, the “mail clerk” is a concrete implementation of the SoapTransport class. Each particular network technology has its own SoapTransport implementation – WSE2 ships with implementations for TCP and HTTP, and it’s possible to extend the architecture to other transports by implementing custom derivations of SoapTransport. A SoapTransport implementation is responsible for maintaining a pool of network resources over which messages might arrive. The TCP transport, for example, maintains a set of TCP sockets in “listen” mode. Similarly, an MSMQ transport might maintain a pool of MessageQueue objects. As such, the transport serves as an abstraction barrier between the network and the rest of the messaging architecture. It encapsulates the details of the underlying network so that they are hidden from higher layers of the messaging stack.

In my office, every person has a mailbox that stores incoming mail until the recipient gets around to picking it up. When the mailman arrives at my office building, he leaves a large bundle of incoming mail with the mail clerk. The mail clerk is responsible for looking at the address of each letter and delivering it to the proper mailbox. In WSE2, the analogy to “mailbox” is an ISoapInputChannel implementation. An InputChannel is like a mailbox for services – it stores messages that are addressed to a specific service until that service can come and pick them up.

The transport class is responsible for the creation and maintenance of input channels. Every SoapTransport must implement ISoapTransport.GetInputChannel( EndpointReference epr, SoapChannelCapabilities c ). This method opens an input channel on a specific endpoint. As part of the GetInputChannel() operation, the transport class must open a new network resource (exactly which network resource is derived from the EndpointReference.TransportAddress property, according to the semantics of the transport). For example, as part of opening an InputChannel on the “soap.tcp://localhost:2323” URI, the TCP transport might open a TCP socket on port 2323 – but in general it’s up to each individual transport implementation to determine how to map transport addresses into network resources. The transport must also store the newly created input channel in an internal collection (conveniently implemented by the SoapTransport.InputChannels collection), so it can deliver messages to that channel when they arrive later.

Just like the mail clerk, the SoapTransport implementation must look at the address of each incoming message and deliver it to the appropriate InputChannel. This operation can be done generically for all transport (thanks to the transport-independent addressing mechanism that WS-Addressing provides). As such, dispatch logic is implemented in a single place – SoapTransport.DispatchMessage(). Thus, when a message arrives on a the network, the transport is responsible for deserializing that message from the network and calling SoapTransport.DispatchMessage(). DispatchMessage() then looks at the addressing headers of the message and matches them against the all of the active InputChannels the transport maintains in its InputChannels collection. If a match is found, dispatch message calls InputChannel.Enqueue to store the message in the InputChannel.

When a message arrives in my office mailbox, it stays there until I pick it up. Similarly, messages stay buffered in an InputChannel until the service that opened the channel can come along and process it. Realistically, I don’t think that messages really accumulate inside of the InputChannel because the service infrastructure picks them up almost as soon as they come in – but conceptually, the InputChannel offers the same buffering capabilities as a real mailbox.

The problem with my office mailroom is that I periodically have to poll my mailbox for new messages. Being the lazy programmer that I am, what I’d really like is for an intern to watch my inbox for me and run over to my office with the new message every time one arrives. WSE2 allows services a similar degree of laziness; the service class (whatever concrete subtype of SoapReceiver that happens to be) is not responsible for monitoring the status of its input channels directly. Instead, there’s an intermediary – an intern, if you will, that takes care of delivering the message from the input channel to the SoapReceiver automatically. This “intern” is the SoapReceivers collection.

In order to register a listening service, you must register it with the SoapReceivers collection by calling SoapReceivers.Add( EndpointReference epr, SoapReceiver receiver). This binds a service instance to an endpoint and starts the messaging infrastructure listening for messages on that endpoint. Internally, this is accomplished by finding the appropriate instance of SoapTransport based upon the URI scheme of the endpoint’s TransportAddress, and then calling GetInputChannel() on that transport. The SoapReceivers collection can then call BeginReceive() on that InputChannel, registering a generic dispatch function as a callback. Thus, whenever a message arrives on that InputChannel, the callback will be invoked and the SoapReceivers collection can deliver that message from the InputChannel to the waiting service. It’s exactly the same effect as having someone run up to your office every time a message arrives in your mailbox, only it’s accomplished with async callbacks and no interns.

In summary, delivering a message to your office is a series of the following asynchronous operations:

 

1)      Postal carrier delivers letter to mailroom.

2)      Mail clerk delivers it to your mailbox.

3)      Intern runs it to your office.

 

The corresponding sequence of asynchronous events in WSE2 is as follows:

 

1)      Message arrives on network resource

2)      Transport dispatches it to an InputChannel

3)      The SoapReceivers collection dispatches it to the service class

 

I’ll talk more about what I see as the benefits of this architecture later. I’ll also be talking more about the mechanics of accomplishing all of this via a custom transport implementation in future posts.

 


Read comments or post a reply to : Transports, channels, and the office mailroom
Page 20037 of 20217

Newest posts
 

    Email TopXML