How the WCF Service Runtime Dispatches Operations


Before looking in detail at how you can build a WCF service that routes messages to other services, it is useful to explain a little more about what happens when a WCF service actually receives a request message from a client application.

ChannelDispatcher and EndpointDispatcher Objects Revisited

In Chapter 10, “Programmatically Controlling the Configuration and Communications,” you saw that the WCF runtime for a service creates a channel stack for each distinct address and binding combination used to communicate with the service. Each channel stack has a ChannelDispatcher object and one or more EndpointDispatcher objects. The purpose of the ChannelDispatcher object is to determine which EndpointDispatcher object should handle the message. The role of the EndpointDispatcher object is to convert the message into a method call and invoke the appropriate method in the service.

Note 

This is a very simplified view of the WCF Service Model. The EndpointDispatcher object does not directly invoke the method in the service itself. It uses a number of other helper objects instantiated by the WCF runtime. These objects have their own specific responsibilities for converting the message into a method call, selecting the appropriate service instance, handling the value returned by the method, and all the other low-level tasks associated with executing an operation. The WCF runtime is highly customizable, and you can replace many of the standard objects provided by WCF that perform these tasks with your own implementations.

Each address and binding combination exposed by a service can be shared by multiple endpoints. For example, the configuration file for the ProductsServiceV2 solution from Chapter 6, “Maintaining Service Contracts and Data Contracts,” defined the following service and endpoints:

 <services>   <service … name="Products.ProductsServiceImpl">     <endpoint       address="https://localhost:8000/ProductsService/ProductsService.svc"       binding="basicHttpBinding" name="ProductsServiceHttpEndpoint"       contract="Products.IProductsService" />     <endpoint address="net.tcp://localhost:8080/TcpProductsService"       binding="netTcpBinding" name="ProductsServiceTcpBinding"       contract="Products.IProductsService" />     <endpoint       address="http://localhost:8010/ProductsService/ProductsService.svc"       binding="wsHttpBinding" name="ProductsServiceWSHttpEndpoint"       contract="Products.IProductsService" />     <endpoint       address="https://localhost:8000/ProductsService/ProductsService.svc"       binding="basicHttpBinding" name="ProductsServiceHttpEndpointV2"       contract="Products.IProductsServiceV2" />     <endpoint address="net.tcp://localhost:8080/TcpProductsService"       binding="netTcpBinding" name="ProductsServiceTcpBindingV2"       contract="Products.IProductsServiceV2" />     <endpoint       address="http://localhost:8010/ProductsService/ProductsService.svc"       binding="wsHttpBinding" name="ProductsServiceWSHttpEndpointV2"       contract="Products.IProductsServiceV2" />   </service> </services>

Notice that this configuration defines six endpoints, but that there are only three distinct address/binding combinations. Consequently, this configuration causes the WCF runtime to create three channel stacks, each with its own ChannelDispatcher object. Each channel stack is associated with two possible endpoints; one for each of the contracts available through that channel stack. The WCF runtime creates two EndpointDispatcher objects for each channel stack and adds them to the collection of EndpointDispatcher objects associated with the ChannelDispatcher object. Figure 13-1 shows the relationship between the endpoints, channel stacks, and dispatcher objects for this service.

image from book
Figure 13-1: Channels and Dispatchers for the ProductsServiceImpl service.

When the service receives a message on a channel, the ChannelDispatcher object at the top of the channel stack queries each of its associated EndpointDispatcher objects to determine which endpoint can process the message. If none of the EndpointDispatcher objects can accept the message, the WCF runtime raises the UnknownMessageReceived event on the ServiceHost object hosting the service. Chapter 3, “Making Applications and Services Robust,” describes how to handle this event.

EndpointDispatcher Objects and Filters

How does an EndpointDispatcher object indicate that it can process a message? Well, an EndpointDispatcher object exposes two properties that the ChannelDispatcher can query. These properties are AddressFilter and ContractFilter.

The AddressFilter property is an instance of the EndpointAddressMessageFilter class. The EndpointAddressFilterMessage class provides a method called Match that takes a message as its input parameter and returns a Boolean value indicating whether the EndpointDispatcher object recognizes the address contained in the header of this message or not.

The ContractFilter property is an instance of the ActionMessageFilter class. This class also provides a Match method that takes a message as its input parameter, and it returns a Boolean value indicating whether the EndpointDispatcher object can handle the action specified in the message header. Remember that the action identifies the method that the EndpointDispatcher will invoke in the service instance if it accepts the request. Internally, the ActionMessageFilter object contains a table of actions, held as strings, and all the Match method does is iterate through this table until it finds a match or reaches the end of the table.

The Match method in both filters must return true for the ChannelDispatcher object to consider sending the message to the EndpointDispatcher object for processing. It is also possible for more than one EndpointDispatcher object to indicate that it can handle the message. In this case, the EndpointDispatcher class provides the FilterPriority property. This property returns an integer value, and an EndpointDispatcher object can indicate its relative precedence compared to other EndpointDispatcher objects by returning a higher or lower number. If two matching endpoints have the same priority, the WCF runtime throws a MultipleFilterMatchesException exception.

The WCF runtime creates the EndpointAddressFilterMessage and ActionMessageFilter objects for each ChannelDispatcher object based on the endpoint definitions in the service configuration file (or in code, if you are creating endpoints dynamically by using the AddServiceEndpoint method of the ServiceHost object, as described in Chapter 10). You can override these filters by creating your own customized instances of these objects with your own address and table of actions and inserting these filters when the WCF runtime builds the service prior to opening it. One way to do this is to create a custom behavior, as you did when adding the message inspector in Chapter 10.

By default, the EndpointDispatcher invokes the method corresponding to the action in the service contract. However, you can modify the way in which the EndpointDispatcher processes an operation request by creating a class that implements the IDispatchOperationSelector interface and assigning it to the OperationSelector property of the DispatchRuntime object referenced by the DispatchRuntime property of the EndpointDispatcher. This interface contains a single method called SelectOperation:

public string SelectOperation(ref Message message).

You can use this method to examine the message and return the name of a method that the EndpointDispatcher should invoke to handle it. This is useful if you want to manually control the way in which the dispatching mechanism works.

More Info 

The Custom Demux sample included with the WCF samples in the Microsoft Windows SDK provides more information on creating an endpoint behavior class that overrides the contract filter and operation selector for an endpoint dispatcher. This sample is based on the MsmqIntegrationBinding binding, but the general principles are the same for other bindings. You can find this sample online at http://windowssdk.msdn.microsoft.com/enus/library/ms752265.aspx.

To summarize, the dispatching mechanism provides a highly customizable mechanism for determining which endpoint should process a message. You can make use of this knowledge to build services that can transparently route messages to other services.




Microsoft Windows Communication Foundation Step by Step
Microsoft Windows Communication Foundation Step by Step (Step By Step Developer Series)
ISBN: 0735623368
EAN: 2147483647
Year: 2007
Pages: 105
Authors: John Sharp

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net