In .NET 4 there will be the Routing Service, which will serve to fill the gap between clients and services that previously existed in WCF. Great! But what are we really giving you beyond a simple proxy? Intermediaries can be chock full of features, and serve a whole variety of needs. Instead of first talking about features, I'm going to give a quick set (off the top of my head) of our priorities when we built the Routing Service.
- Build something generic, extensible, and flexible
- We want the Routing Service to be usable in a whole pile of scenarios and patterns. This is designed as a core communications component inside the .NET Framework. People should be able to take this component and utilize it 100's of different ways.
- No need to solve problems that have already been solved, or to build functionality in V1 that could be added easily in V2 (or by extensibility after we ship).
- This is V1, focus on providing an excellent base component that others can build on, extend, and which provides a foundation for the future. Don't "solve world hunger".
- Performance, security, and scale are all considerations and need to be thought of as features as much of the messaging capabilities.
So this is all well and good, but what did we actually build? 🙂 What can the Routing Service do?
It turns out there four major capabilities that the Routing Service gives you:
- Content Based Routing - As a message comes in, examine it, and determine whether it should be sent to one or many destinations. We take care of this by giving you a surface for plugging in MessageFilters (a standard WCF component) and mapping them to destination endpoints within a MessageFilterTable. Of course, you can also build your own MessageFilter and use that if the ones we provide out of the box don't work for you. The messageFilters that we provide out of the box are Address, AddressPrefix, EndpointName, AND, XPath, and MatchAll, as well as the ability to define and utilize your own.
- Protocol Bridging - WCF Services can speak in a variety of transports and protocols, and there's no reason that the Routing Service shouldn't be able to convert between one and another for you. Luckily it does 🙂 Want to expose your services via BasicHttp for interoperability, but want your services to use net.tcp for speed internally? No problem! Configure the Routing Service's inbound binding to be BasicHttp, and tell it to speak to your back-end services in net.tcp. Done. The Routing Service will automatically take the message that arrived from the client in Soap1.1 and convert it to Soap1.2 for sending to your destination service. Similarly, if there's a response that needs to go back, the Routing Service will handle converting it back so that the client receives a message it can understand.
- Error Handling - This being the real world, machines go down, network glitches or temporary slowdowns happen, and services are occasionally non-responsive for no good reason. When your client is tied directly to a single service being affected by one or more of these problems, it can lead to problems and increase the complexity of your design. You end up having to write logic to handle these capricious errors and exceptions. Worse, if you're dealing with complex messaging patterns, it can be hard to get this logic right. In the Routing Service we give you the ability to define a list of endpoints, such that if the first one in the list is down, the Routing Service will automatically fail-over to the next one in the list. This gives you a quick way to add reliability to your application without having to teach your client application how to handle complex patterns or where all of your services are deployed. Multicasting a one way transacted session of messages at the Routing Service and wondering what happens when node n out of 4 is down/unresponsive? Don't, we've got it covered!
- Dynamic Reconfiguration - All of this is well and good, but what do I do when my deployment pattern changes? What do I do when I add a new type of service and need to get my Routing Service to start routing messages to it, wherever it's deployed? How do I deploy 10 new instances of a particular service and get them all added into the Routing Service's list of backups? And I need to be able to do this without recycling my host or writing a ton of my own code. This capability was one of the major requests from our customers, and I'm glad that we were able to provide something that met their needs. In V1 the Routing Service will provide a service Extension (RoutingExtension), and an Object that contains all of the configuration information that a Router needs to function (creatively named RoutingConfiguration). At runtime, you can register your own extension which periodically creates a new RoutingConfiguration object, gives it all of the (updated) data necessary, and then hands that RoutingConfiguration object to our RoutingExtension. At this point, the RoutingService will begin using the updated configuration information for new messages and sessions, while leaving in-flight messages/sessions using whatever rules were in place when they started. This gives you the ability to do session-safe, recycle-less reconfiguration of the Routing Service during runtime.
We feel like each of these was necessary in order to deliver a solid generic message router in V1 (of course you may disagree, or think we left something out. If this is the case, I'd love to hear from you in the comments).
I'll cover each of these in more detail in future posts, but hopefully you've already got some ideas about how you could use these capabilities when you're writing your WCF applications.