WCF Routing and discovery
Routing
MSDN scenarios
Routers have one or more client endpoints, and expose a service endpoint...
- it has a binding of IRequestReplyRouter (or applicable protocol- OneWay is ISimplexDatagramRouter, or IDuplexSessionRouter). You shouldn't mix them (expose different endpoints, although DuplexSessionRouter is a workaround)
- it has a behaviorConfiguration with routing filterTableName="routingTable1"
- it has a routing section containing
- filters: named message filters
- MatchAllFilter matches everything
- ActionMessageFilter for specific actions (the SOAP Action name is {method}Request and {method}Response e.g. DoWorkRequest)
- Also filters for EndpointName, XPath (with filterData - use namespaces), Custom...
- Filters have priorities - set higher priorities to be taken first
- filterTables: mapped filters to clients, filterTable/filters/add filterName endpointName.
- filters: named message filters
<system.serviceModel>
<routing>
<filters>
<!-- filter logic -->
<filter name="MatchAllFilter" filterType="MatchAll"/>
</filters>
<filterTables>
<filterTable>
<!--map filter to endpoint-->
<add filterName="MatchAllFilter" endpointName="fwdEndpoint"/>
</filterTable>
</filterTables>
</routing>
You can multicast (but not for request-reply as you'd get several replies!).
Each client endpoint can have a backupList (points to backupLists/backupList which is a list- it just works it's way down the list when it gets Timeouts or communication exception).
Code
You should host in IIS with configuration.
<%@ ServiceHost Language="C#"
Service="System.ServiceModel.Routing.RoutingService,
System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" %>
Here's a self-hosted version.
//create the service
var serviceHost = new ServiceHost(typeof(RoutingService));
//add the router endpoint
serviceHost.AddServiceEndpoint(
//request-reply type
typeof(IRequestReplyRouter),
new WSHttpBinding(),
"http://localhost/routingservice/router");
//add the client endpoint(s)- forwards the messages here
var client = new ServiceEndpoint(
//use the router contract
ContractDescription.GetContract(typeof(IRequestReplyRouter)),
new WSHttpBinding(),
new EndpointAddress("http://localhost/calculatorservice"));
//routing configuration
var rc = new RoutingConfiguration();
//a list of the clients
var endpointList = new List<ServiceEndpoint> { client };
//filter all messages to these clients
rc.FilterTable.Add(new MatchAllMessageFilter(), endpointList);
//attach the behavior to the service host
serviceHost.Description.Behaviors.Add(new RoutingBehavior(rc));
Discovery
MSDN. Reference System.ServiceModel.Discovery.dll
Announce a service
By default, there are no announcements. Add an announcementEndpoint to the discovery behavior.
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceDiscovery>
<announcementEndpoints>
<endpoint name="udpEndpoint"
kind="udpAnnouncementEndpoint" />
</announcementEndpoints>
</serviceDiscovery>
</behavior>
</serviceBehaviors>
- An endpoint can have scopes (a uri- behavior/endpointDiscovery/scopes/add). Useful for versioning (v1/v2), production/test etc.
You can create an AnnouncementService, subscribe to its events (Online/OfflineAnnouncementReceived), and put it in a ServiceHost to selfhost with an UdpAnnouncementEndpoint.
Client discovery
The client sends a multicast Probe with Find with FindCriteria. You can set ContractTypeNames (each endpoint must match all these contracts). It returns zero or more records for services that support the criteria.
private EndpointAddress DiscoverServices()
{
FindResponse findResponse;
using (var discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint()))
{
findResponse = discoveryClient.Find(new FindCriteria(typeof (ICalculatorService)));
}
return !findResponse.Endpoints.Any() ? null :
findResponse.Endpoints.First().Address;
}
- Add FindCriteria.MaxResults = 1 to speed it up unless you want to multicast.
- FindCriteria.Scopes.Add(new Uri("http://v1")) to look for scopes (see above)
A client can use DynamicEndpoint instead of a normal endpoint. Each time it is used, it discovers which endpoint it can use. Specify the contract description:
var contractDescription = ContractDescription.GetContract(typeof(ICalculator));