In the previous post, I talked about the primary features of the Routing Service. In this post, I'd like to dive into Content Based Routing (CBR), and talk about some of the design and implementation choices we made.
The model for CBR in the routing Service is a WCF MessageFilterTable<IEnumerable<ServiceEndpoint>> (we'll touch on why there's an IEnum there later), where a MessageFilter that makes some claim about the Message data mapped to a destination set of IEnumerable<ServiceEndpoint> on the right. When a Message comes in, it's content is evaluated by each MessageFilter in the table, which either results in a True (this filter matches this message) or a False (it doesn't). If True, then the destination endpoint(s) is added to a list of destinations that the message should be sent to.
In the Routing Service we've taken MessageFilterTable model and first-classed it, allowing you to directly configure a MessageFilterTable and a set of MessageFilters and ServiceEndpoints. This table then plugs into the RoutingService to serve as the instructions that it should use for examining messages and then sending them to the destinations indicated. By default, we allow MessageFilters to look at the SOAP envelope portio of the message, but you can also configure filters to look at the Body of the message. Looking at the body is useful if you want to route the message on customer/application/call content rather than on addressing or other envelope data.
There were several design considerations that we made when we built the CBR capabilities within the Routing Service that made the reuse of the MessageFilterTable and MessageFilters particularly apt:
- Typelessness - The Routing Service operates in a typeless way from start to finish, handling calls and manipulating data via the WCF Message object. This means that it doesn't know the .NET types or operations used in the clients and services that are passing messages through it. While this makes it easier for the Routing Service to handle many different types of clients and services, it means that you (generally) won't be able to interact with the strong types you're accustomed to accessing inside your clients and services. It also means that we needed to provide a generic and extensible way of interacting with Messages in order to determine where they should go. Luckily, MessageFilters and MessageFilterTables all operate on the Message object, so this design choice matches up rather nicely. We allow you to extend the base set of MessageFilters that we ship by letting you write a class like MyMessageFilter : MessageFilter. The Routing Service's MessageFilterTable would accept and pass Messages to MyMessageFilter for evaluation just like any other MessageFilter.
- Statelessness - The Routing Service is designed to be stateless. There is of course some runtime state (such as the objects we use to maintain a correlation between the requests we recieve from clients and the responses we get from services so that we know which clients to send them back to) but this state is not meant to be durable or to exist longer than we need to keep it around in order to do the necessary work. This design consideration extends to the CBR capabilities as well. By default, none of the filters we provide have any stateful information which exists longer than it takes a particular message to be processed. As with a stateless service, this is a performance boon, as it means there is no internal state to store or refresh, or to which needs be maintained across calls or between different filters. However it also means that building a filter which maintains its state across calls is tricky (though not impossible). I'll discuss some of the ways you can shoehorn stateful filtering into the Routing Service (and some of the reasons you may want to) in a future post, but I'd like to emphasize up front that in general we believe that stateless solutions will yield better results, and that once you transition to using runtime state you're no longer talking about routing based purely on message content.
Now that we've discussed some of the why and how of Content Based Routing, the next post will deal with some examples and how to configure them.