// In this tutorial, the routing service is hosted using a console application to avoid over-complicating the routing // proof of concept with complex IIS, hosting, and web.config configurations. The console hosts can be easily tested // without any configuration necessary static void Main(string[] args) { // I am sure that you realize that all of the following could be done in the web.config, but I opted to do it // programmitically so that each individual component can be explained along the way using (var host = new ServiceHost(typeof(RoutingService))) { // In this step, we create an BasicHttp binding endpoint that will be used by the hosting interface to // expose our routing service. // Note the use of the IRequestReplyRouter contract ContractDescription contract = ContractDescription.GetContract(typeof(IRequestReplyRouter)); Binding binding = new BasicHttpBinding(); var endpointAddress = new EndpointAddress("http://*****:*****@"http://services.bloggedbychris.com/practice/routing/v1/Version/GetVersion"); var v1Endpoint = new [] {new ServiceEndpoint(contract, new BasicHttpBinding(), new EndpointAddress("http://*****:*****@"http://services.bloggedbychris.com/practice/routing/v2/Version/GetVersion"); var v2Endpoint = new[] {new ServiceEndpoint(contract, new BasicHttpBinding(), new EndpointAddress("http://localhost:9092/routing/version/"))}; routingConfiguration.FilterTable.Add(v2Filter, v2Endpoint); // Here we add our routing configuration as a service behavior for our routing service var routingBehavior = new RoutingBehavior(routingConfiguration); host.Description.Behaviors.Add(routingBehavior); // Open the ServiceHost to create listeners // and start listening for messages. host.Open(); // The service can now be accessed. Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); } }
private static void ConfigureRouterViaCode(ServiceHost serviceHost) { //This code sets up the Routing Sample via code. Rename or delete the App.config file //and comment out this method call to run a config-based Routing Service //set up some communication defaults string deadAddress = "net.tcp://localhost:9090/servicemodelsamples/fakeDestination"; string realAddress = "net.tcp://localhost:8080/servicemodelsamples/service"; string routerAddress = "http://localhost/routingservice/router"; //note that the calculator client will be communicating to the Routing Service via basic //HTTP, while the Routing Service is using Net.TCP to communicate to the calculator service. //This demonstrates the Routing Service's capability of bridging between different message //transports, formats, bindings, etc. This automatic message conversion is governed by //whether or not SoapProcessing (enabled by default) is enabled on the Routing Configuration. Binding routerBinding = new BasicHttpBinding(); Binding clientBinding = new NetTcpBinding(); //add the endpoint the router will use to recieve messages serviceHost.AddServiceEndpoint(typeof(IRequestReplyRouter), routerBinding, routerAddress); //create the client endpoint the router will route messages to //note that the contract description on the client endpoints is actually unused, so //this could be any string. The contract specified here goes unused //because the Routing Service replaces this contract with one of the Router //contracts at runtime, depending on the contract that a message was received with. ContractDescription contract = new ContractDescription("IRequestReplyRouter"); ServiceEndpoint fakeDestination = new ServiceEndpoint(contract, clientBinding, new EndpointAddress(deadAddress)); ServiceEndpoint realDestination = new ServiceEndpoint(contract, clientBinding, new EndpointAddress(realAddress)); //create the endpoint list that contains the service endpoints we want to route to List<ServiceEndpoint> backupList = new List<ServiceEndpoint>(); //add the endpoints in the order that the Routing Service should contact them //first add the endpoint that we know will be down //clearly, normally you wouldn't know that this endpoint was down by default backupList.Add(fakeDestination); //then add the endpoint that will work //the Routing Service will attempt to send to this endpoint only if it //encounters a TimeOutException or CommunicationException when sending //to the previous endpoint in the list. backupList.Add(realDestination); //create the default RoutingConfiguration option RoutingConfiguration rc = new RoutingConfiguration(); //add a MatchAll filter to the Routing Configuration's filter table //map it to the list of endpoints defined above //when a message matches this filter, it will be sent to the endpoints in the list in order //if an endpoint is down or doesn't respond (which the first client won't //since no service exists at that endpoint), the Routing Service will automatically move the message //to the next endpoint in the list and try again. rc.FilterTable.Add(new MatchAllMessageFilter(), backupList); //create the Routing Behavior with the Routing Configuration and add it to the //serviceHost's Description. serviceHost.Description.Behaviors.Add(new RoutingBehavior(rc)); }
public RoutingBehavior(RoutingConfiguration routingConfiguration) { if (routingConfiguration == null) { throw FxTrace.Exception.ArgumentNull("routingConfiguration"); } this.configuration = routingConfiguration; }
private static void Main(string[] args) { const string routerAddress = "http://localhost:8001/router"; using (var routerHost = new ServiceHost(typeof(RoutingService), new Uri(routerAddress))) { Binding routerBinding = new BasicHttpBinding(); routerHost.AddServiceEndpoint(typeof(IRequestReplyRouter), routerBinding, string.Empty); Binding greetingBinding = new NetTcpBinding(); const string greetingBase = "net.tcp://localhost:8000/GreetingService/"; var contractDescription = ContractDescription.GetContract(typeof(IRequestReplyRouter)); var helloEndpoint = new ServiceEndpoint(contractDescription, greetingBinding, new EndpointAddress(greetingBase + "Hello")); var goodbyeEndpoint = new ServiceEndpoint(contractDescription, greetingBinding, new EndpointAddress(greetingBase + "Goodbye")); var routerConfig = new RoutingConfiguration(); IEnumerable<ServiceEndpoint> helloEndpoints = new List<ServiceEndpoint> { helloEndpoint, }; routerConfig.FilterTable.Add(new ActionMessageFilter("Hello"), helloEndpoints); IEnumerable<ServiceEndpoint> goodbyeEndpoints = new List<ServiceEndpoint> { goodbyeEndpoint, }; routerConfig.FilterTable.Add(new ActionMessageFilter("Goodbye"), goodbyeEndpoints); routerHost.Description.Behaviors.Add(new RoutingBehavior(routerConfig)); routerHost.Open(); Console.WriteLine("Routing service ready."); do { Console.WriteLine("Press <ESC> to exit."); } while (Console.ReadKey(true).Key != ConsoleKey.Escape); Console.WriteLine("Exiting..."); routerHost.Close(); } }
private static void ConfigureRouterViaCode(ServiceHost serviceHost) { //This code sets up the Routing Sample via code. Rename or delete the provided //App.config and uncomment this method call to run a code-based Routing Service //set up some communication defaults string clientAddress = "http://localhost:8000/servicemodelsamples/service"; string routerAddress = "http://localhost:8000/routingservice/router"; Binding routerBinding = new WSHttpBinding(); Binding clientBinding = new WSHttpBinding(); //add the endpoint the router will use to recieve messages serviceHost.AddServiceEndpoint(typeof(IRequestReplyRouter), routerBinding, routerAddress); //create the client endpoint the router will route messages to ContractDescription contract = ContractDescription.GetContract(typeof(IRequestReplyRouter)); ServiceEndpoint client = new ServiceEndpoint(contract, clientBinding, new EndpointAddress(clientAddress)); //create a new routing configuration object RoutingConfiguration rc = new RoutingConfiguration(); //create the endpoint list that contains the service endpoints we want to route to //in this case we have only one List<ServiceEndpoint> endpointList = new List<ServiceEndpoint>(); endpointList.Add(client); //add a MatchAll filter to the Router's filter table //map it to the endpoint list defined earlier //when a message matches this filter, it will be sent to the endpoint contained in the list rc.FilterTable.Add(new MatchAllMessageFilter(), endpointList); //attach the behavior to the service host serviceHost.Description.Behaviors.Add(new RoutingBehavior(rc)); }
private static void ConfigureRouterViaCode(ServiceHost serviceHost) { //This code sets up the Routing Sample via code. Rename the provided app.config //to App.config.example and uncomment this method call to run a config-based Routing Service //set up some communication defaults //note that some of these are a little artifical for the purpose of demonstrating //different filter types and how to define them //the regular calculator service is located at net.tcp://localhost:9090/servicemodelsamples/service/ string calcDestinationAddress = "net.tcp://localhost:9090/servicemodelsamples/service/"; //the rounding calc service is located at net.tcp://localhost:8080/servicemodelsamples/service/ string roundingDestinationAddress = "net.tcp://localhost:8080/servicemodelsamples/service/"; //the "Default" router address string routerAddress = "http://localhost/routingservice/router/general"; //the virtualized address of the regular calculator string virtualCalculatorAddress = "http://localhost/routingservice/router/regular/calculator"; //the virtualized address of the rounding calculator string virtualRoundingCalculatorAddress = "http://localhost/routingservice/router/rounding/calculator"; //set up the bindings for the Routing Service's communication with the client Binding routerBinding = new WSHttpBinding(); //set up the bindings for the Routing Service's communication with the Calculator Services Binding clientBinding = new NetTcpBinding(); //use the IRequestReplyRouter since the client and services are expecting request/response communication ContractDescription contract = ContractDescription.GetContract(typeof(IRequestReplyRouter)); //set up the default Router endpoint ServiceEndpoint routerEndpoint = new ServiceEndpoint(contract, routerBinding, new EndpointAddress(routerAddress)); routerEndpoint.Name = "routerEndpoint"; //create the virtual endpoint for the regular CalculatorSerivice ServiceEndpoint calcEndpoint = new ServiceEndpoint(contract, routerBinding, new EndpointAddress(virtualCalculatorAddress)); calcEndpoint.Name = "calculatorEndpoint"; //create the virtual endpoint for the rounding CalculatorSerivice ServiceEndpoint roundingEndpoint = new ServiceEndpoint(contract, routerBinding, new EndpointAddress(virtualRoundingCalculatorAddress)); roundingEndpoint.Name = "roundingEndpoint"; //add the inbound endpoints that the Routing Service will listen for serviceHost.AddServiceEndpoint(routerEndpoint); serviceHost.AddServiceEndpoint(calcEndpoint); serviceHost.AddServiceEndpoint(roundingEndpoint); //create the client endpoints the router will route messages to ServiceEndpoint RegularCalcEndpoint = new ServiceEndpoint(contract, new NetTcpBinding(), new EndpointAddress(calcDestinationAddress)); ServiceEndpoint RoundingCalcEndpoint = new ServiceEndpoint(contract, new NetTcpBinding(), new EndpointAddress(roundingDestinationAddress)); //create the endpoint lists that contains the service endpoints we want to route to List<ServiceEndpoint> RegularCalcs = new List<ServiceEndpoint>(); List<ServiceEndpoint> RoundingCalcs = new List<ServiceEndpoint>(); //add the endpoints in the order we want the Routing Service to try sending to them RegularCalcs.Add(RegularCalcEndpoint); RoundingCalcs.Add(RoundingCalcEndpoint); //create the default RoutingConfiguration RoutingConfiguration rc = new RoutingConfiguration(); //create all of the necessary filters //create a new XPathMessageFilter that will look for the custom header //Unfortunately, the default namespace manager doesn't have the custom namespace // that we use defined so we have to define that prefix ourselves. //Any message that shows up with this header will match this filter. XPathMessageContext namespaceManager = new XPathMessageContext(); namespaceManager.AddNamespace("custom", "http://my.custom.namespace/"); XPathMessageFilter xpathFilter = new XPathMessageFilter("sm:header()/custom:RoundingCalculator = 1", namespaceManager); //create a new Endpoint Name Message Filter, which will match any message that was received //on the calculator Endpoint. The Endpoint name was defined when we created the service endpoint object EndpointNameMessageFilter endpointNameFilter = new EndpointNameMessageFilter("calculatorEndpoint"); //Create a new Prefix Endpoint Address Message Filter. This will match any message that showed up on an endpoint //with an address that matches the address -prefix- (or front portion) provided. In this example we define //the address prefix as "http://localhost/routingservice/router/rounding/". This means that any messages that arrive //addressed to http://localhost/routingservice/router/rounding/* will be matched by this filter. In this case, that //will be messages that show up on the rounding calculator endpoint, which has the address of //http://localhost/routingservice/router/rounding/calculator. PrefixEndpointAddressMessageFilter prefixAddressFilter = new PrefixEndpointAddressMessageFilter(new EndpointAddress("http://localhost/routingservice/router/rounding/")); //create two new Custom message filters. In this example, we're going to use a "RoundRobin" message filter //this message filter is created in the provided RoundRobinMessageFilter.cs file. These filters, when set //to the same group, will alternate between reporting that they match the message and that they don't, such that //only one of them will respond true at a time. RoundRobinMessageFilter roundRobinFilter1 = new RoundRobinMessageFilter("group1"); RoundRobinMessageFilter roundRobinFilter2 = new RoundRobinMessageFilter("group1"); //Now let's add all of those Message Filters to the Message Filter Table //note the use of priorities to influence the order in which the MessageFilter Table //executes the filters. The higher the priority, the sooner the filter will be //executed, the lower the priority, the later a filter will be executed. Thus a filter //at priority 2 runs before a filter at priority 1. The default priority level //if one isn't specified is 0. A Message Filter Table executes all of the filters //at a given priority level before moving to the next lowest priority level. //If a match is found at a particular priority, then the Message Filter Table doesn't //continue trying to find matches at the next lower priority. // //While this example shows how to use Message Filter priorities, in general it is //more performant and better design to design and configure your filters such that they //don't require prioritization in order to function correctly. //The first filter we add is the XPath filter, and we set its priority to 2. //Thus this will be the first MessageFilter that executes. If it finds the custom //header, regardless of what the results of the other filters would be, the message //will be routed to the Rounding Calculator endpoint. //catch messages that showed up with the custom header rc.FilterTable.Add(xpathFilter, RoundingCalcs, 2); //At priority 1, we'll add two filters. These will only run if the xpath filter //at priority 2 doesn't match the message. These two filters show two different ways to //determine where the message was addressed when it showed up. Because they effectively check //to see if the message arrived at one of the two endpoints, we can run them //at the same priority level since they're never going to both return true. //find messages that showed up addressed to the specific virtual endpoints rc.FilterTable.Add(endpointNameFilter, RegularCalcs, 1); rc.FilterTable.Add(prefixAddressFilter, RoundingCalcs, 1); //Finally, run the RoundRobin message filters. Since we configured the filters //with the same group name, only one of them will match at a time. Since we've already //Routed all the messages with the custom header, and then those addressed to the specific //virtualized endpoints, these will only be messages that showed up addressed to the //default router endpoint without the custom header. Since these will switch based //on a per message call, half of the operations will go to the regular calculator, and //half will go to the Rounding calculator. rc.FilterTable.Add(roundRobinFilter1, RegularCalcs, 0); rc.FilterTable.Add(roundRobinFilter2, RoundingCalcs, 0); //create the Routing Behavior with the Routing Configuration and add it to the //serviceHost's Description. serviceHost.Description.Behaviors.Add(new RoutingBehavior(rc)); }
// Remove a MessageFilter from the RouterTable void removeRouting(Filter filter) { lock (this.routingTableLock) { var table = deltaTable(filter); var config = new RoutingConfiguration(table, true); this.Router.Extension.ApplyConfiguration(config); } log.Info("A stale MessageFilter has been removed."); }
public InstanceProvider(RoutingConfiguration config) { this.config = config; }
private static void ConfigureRouterViaCode(ServiceHost host) { //configure a MSMQ Binding that is not very tolerant of failures. MsmqTransportBindingElement msmqbe = new MsmqTransportBindingElement(); //Set the auth mode and protection levels to none so that we can run without //Active Directory using Private queues. msmqbe.MsmqTransportSecurity.MsmqAuthenticationMode = MsmqAuthenticationMode.None; msmqbe.MsmqTransportSecurity.MsmqProtectionLevel = System.Net.Security.ProtectionLevel.None; //when the Routing Service receives a message and is unable to process it, we should reject it. //This will result in the message being placed in the "inbound" queue's System Dead Letter Queue. msmqbe.ReceiveErrorHandling = ReceiveErrorHandling.Reject; msmqbe.DeadLetterQueue = DeadLetterQueue.System; //Set the retry count, retry cycles, and delay to very unreasonable values //If the message cannot be delivered to the destination Queue on the first try //report an error. This error will be noticed by the Routing Service's error //handling code, which will automatically move the message to the backup endpoints //defined, if available. msmqbe.ReceiveRetryCount = 0; msmqbe.MaxRetryCycles = 0; msmqbe.RetryCycleDelay = TimeSpan.FromMilliseconds(1); //create the MSMQ Binding with our custom settings Binding QueueBinding = new CustomBinding(new BinaryMessageEncodingBindingElement(), msmqbe); //add a service endpoint to the host. This is the endpoint on the Routing Service //that reads from the queue. host.AddServiceEndpoint(typeof(ISimplexDatagramRouter), QueueBinding, inboundQ); //create a new RoutingConfiguration object. RoutingConfiguration rc = new RoutingConfiguration(); //create the service endpoints that the Routing Service will communicate with ServiceEndpoint primaryService = new ServiceEndpoint(cd, QueueBinding, new EndpointAddress(primaryServiceQueue)); ServiceEndpoint backupService = new ServiceEndpoint(cd, QueueBinding, new EndpointAddress(backupServiceQueue)); ServiceEndpoint primaryLogging = new ServiceEndpoint(cd, QueueBinding, new EndpointAddress(primaryLoggingQueue)); ServiceEndpoint backupLogging = new ServiceEndpoint(cd, QueueBinding, new EndpointAddress(backupLoggingQueue)); //we always want the message to go to both a service endpoint and a logging endpoint //the way we achieve this is "multicasting" the message to both destinations at the same time //additionally, since we're both the inbound and outbound queues are transactional, if either none of the service queues //or none of the logging queues are able to Transactionally recieve the message, then the Routing Service //will report to the originating system that the message was unable to be delivered, at which point the //originating queue will put the message in it's system Dead Letter Queue. //add the primary service queue and the backup service queue endpoint rc.FilterTable.Add(new MatchAllMessageFilter(), new List<ServiceEndpoint> { primaryService, backupService }); //add the primary logging queue and the backup logging queue endpoint rc.FilterTable.Add(new MatchAllMessageFilter(), new List<ServiceEndpoint> { primaryLogging, backupLogging }); //add the RoutingBehavior to the Service host.Description.Behaviors.Add(new RoutingBehavior(rc)); }
protected RoutingClientBase(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, object callbackInstance, bool impersonating) : base(new InstanceContext(callbackInstance), endpointTrait.Endpoint.Binding, endpointTrait.Endpoint.Address) { Initialize(endpointTrait, routingConfig, impersonating); }
protected RoutingClientBase(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, bool impersonating) : base(endpointTrait.Endpoint.Binding, endpointTrait.Endpoint.Address) { Initialize(endpointTrait, routingConfig, impersonating); }
public RequestReplyClient(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, bool impersonating) : base(endpointTrait, routingConfig, impersonating) { }
public SimplexSessionClient(RoutingEndpointTrait endointTrait, RoutingConfiguration routingConfig, bool impersonating) : base(endointTrait, routingConfig, impersonating) { }
// instance members public RoutingBehavior (RoutingConfiguration routingConfiguration) { if (routingConfiguration == null) throw new ArgumentNullException ("routingConfiguration"); config = routingConfiguration; }