static MessageQuerySet BuildCorrelatesOn() { XPathMessageContext context = new XPathMessageContext(); return new MessageQuerySet() { { "ch", new XPathMessageQuery("//ser:string", context) }, }; }
public override object ProvideValue(IServiceProvider serviceProvider) { XPathMessageContext context = new XPathMessageContext(); foreach (KeyValuePair<string, string> pair in this.namespaces) { context.AddNamespace(pair.Key, pair.Value); } return context; }
// A correlation is initialized in the first Receive activity based on an string identifier from the client. // All following receives follow up on this same correlation key. private static MessageQuerySet BuildCorrelatesOn() { XPathMessageContext context = new XPathMessageContext(); return new MessageQuerySet() { { "CorrH", new XPathMessageQuery("sm:body()/ser:string", context) }, }; }
public XPathMessageContextMarkupExtension(XPathMessageContext context) : this() { foreach (string str in context) { if (!implicitPrefixes.Contains(str)) { this.namespaces.Add(str, context.LookupNamespace(str)); } } }
public static MessageFilterTable<IEnumerable<ServiceEndpoint>> CreateFilterTable(string name) { if (string.IsNullOrEmpty(name)) { throw FxTrace.Exception.ArgumentNullOrEmpty("name"); } RoutingSection routingSection = (RoutingSection)ConfigurationManager.GetSection("system.serviceModel/routing"); if (routingSection == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.RoutingSectionNotFound)); } FilterTableEntryCollection routingTableElement = routingSection.FilterTables[name]; if (routingTableElement == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.RoutingTableNotFound(name))); } XmlNamespaceManager xmlNamespaces = new XPathMessageContext(); foreach (NamespaceElement nsElement in routingSection.NamespaceTable) { xmlNamespaces.AddNamespace(nsElement.Prefix, nsElement.Namespace); } FilterElementCollection filterElements = routingSection.Filters; MessageFilterTable<IEnumerable<ServiceEndpoint>> routingTable = new MessageFilterTable<IEnumerable<ServiceEndpoint>>(); foreach (FilterTableEntryElement entry in routingTableElement) { FilterElement filterElement = filterElements[entry.FilterName]; if (filterElement == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.FilterElementNotFound(entry.FilterName))); } MessageFilter filter = filterElement.CreateFilter(xmlNamespaces, filterElements); //retreive alternate service endpoints IList<ServiceEndpoint> endpoints = new List<ServiceEndpoint>(); if (!string.IsNullOrEmpty(entry.BackupList)) { BackupEndpointCollection alternateEndpointListElement = routingSection.BackupLists[entry.BackupList]; if (alternateEndpointListElement == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.BackupListNotFound(entry.BackupList))); } endpoints = alternateEndpointListElement.CreateAlternateEndpoints(); } //add first endpoint to beginning of list endpoints.Insert(0, ClientEndpointLoader.LoadEndpoint(entry.EndpointName)); routingTable.Add(filter, endpoints, entry.Priority); } return routingTable; }
public RoutingTable() { this.filterTable = new XPathMessageFilterTable<EndpointAddress>(); this.randomNumberGenerator = new Random(); XmlNamespaceManager manager = new XPathMessageContext(); XmlReader routingTableDataFileReader = XmlReader.Create(ConfigurationManager.AppSettings["routingTableXmlFile"]); RoutingTableData routingTableData = (RoutingTableData)new XmlSerializer(typeof(RoutingTableData)).Deserialize(routingTableDataFileReader); foreach (RouterNamespace ns in routingTableData.RouterNamespacesSection.RouterNamespaces) { manager.AddNamespace(ns.Prefix, ns.NamespaceUri); } foreach (Route route in routingTableData.RoutesSection.Routes) { this.filterTable.Add(new XPathMessageFilter(route.XPath, manager), new EndpointAddress(route.Uri)); } }
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)); }
void OnTypeSelectionChanged(object sender, RoutedEventArgs e) { var contentCorrelationDesigner = (ContentCorrelationTypeExpander)sender; //is selection valid (valid type or property) if (contentCorrelationDesigner.IsSelectionValid) { var path = contentCorrelationDesigner.GetMemberPath(); var type = contentCorrelationDesigner.GetSelectedType(); try { XmlNamespaceManager namespaceManager = null; string xpathQuery = string.Empty; var content = this.Activity.Properties["Content"].Value; if (content.IsAssignableFrom<ReceiveMessageContent>() || content.IsAssignableFrom<SendMessageContent>()) { //generating xpath for message content xpathQuery = XPathQueryGenerator.CreateFromDataContractSerializer(type, path, out namespaceManager); } else { //generating xpath for parameter content XName serviceContractName = null; string operationName = null; string parameterName = contentCorrelationDesigner.SelectedTypeEntry.Name; bool isReply = this.Activity.IsAssignableFrom<SendReply>() || this.Activity.IsAssignableFrom<ReceiveReply>(); if (isReply) { operationName = (string)this.Activity.Properties["Request"].Value.Properties["OperationName"].ComputedValue; serviceContractName = (XName)this.Activity.Properties["Request"].Value.Properties["ServiceContractName"].ComputedValue; if (string.IsNullOrEmpty(operationName) || null == serviceContractName) { ModelItem requestDisplayName; this.Activity.TryGetPropertyValue(out requestDisplayName, "Request", "DisplayName"); throw FxTrace.Exception.AsError(new InvalidOperationException( string.Format(CultureInfo.CurrentUICulture, (string)this.FindResource("parametersRequiredText"), requestDisplayName.GetCurrentValue()))); } } else { operationName = (string)this.Activity.Properties["OperationName"].ComputedValue; serviceContractName = (XName)this.Activity.Properties["ServiceContractName"].ComputedValue; if (string.IsNullOrEmpty(operationName) || null == serviceContractName) { throw FxTrace.Exception.AsError(new InvalidOperationException( string.Format(CultureInfo.CurrentUICulture, (string)this.FindResource("parametersRequiredText"), this.Activity.Properties["DisplayName"].ComputedValue))); } } xpathQuery = ParameterXPathQueryGenerator.CreateFromDataContractSerializer(serviceContractName, operationName, parameterName, isReply, type, path, out namespaceManager); } //use CDF api to build a xpath out of type and its properties string xpath = string.Format(CultureInfo.InvariantCulture, "sm:body(){0}", xpathQuery); //get the context //We need to copy over the namespaces from the manager's table 1 by 1. According to MSDN: //If you specify an existing name table, any namespaces in the name table are not automatically added to XmlNamespaceManager. //You must use AddNamespace and RemoveNamespace to add or remove namespaces. XPathMessageContext messageContext = new XPathMessageContext(); foreach (string prefix in namespaceManager) { if (!string.IsNullOrEmpty(prefix) && !messageContext.HasNamespace(prefix) && prefix != "xmlns") { messageContext.AddNamespace(prefix, namespaceManager.LookupNamespace(prefix)); } } var typeEntry = (ExpanderTypeEntry)contentCorrelationDesigner.Tag; //construct xpath XPathMessageQuery query = new XPathMessageQuery(xpath, messageContext); //store the xpath in the Tag property; this combo's selectedValue is bound to i typeEntry.Tag = query; this.SelectedIndex = 0; this.IsDropDownOpen = false; this.Query = query; this.RaiseEvent(new RoutedEventArgs(XPathCreatedEvent, this)); } catch (Exception err) { MessageBox.Show( err.Message, (string)this.Resources["controlTitle"], MessageBoxButton.OK, MessageBoxImage.Error); } } }
static WorkflowService GetService() { Variable<Customer> customer = new Variable<Customer>(); Variable<Order> order = new Variable<Order>(); Variable<string> drug = new Variable<string>(); Variable<double> adjustedCost = new Variable<double>(); Variable<int> percentagePaidByInsurance = new Variable<int>(); Variable<CorrelationHandle> customerHandle = new Variable<CorrelationHandle>(); Variable<CorrelationHandle> orderHandle = new Variable<CorrelationHandle>(); XPathMessageContext pathContext = new XPathMessageContext(); pathContext.AddNamespace("psns", Constants.PharmacyServiceNamespace); MessageQuerySet GetOrderQuerySet = new MessageQuerySet { { "OrderID", new XPathMessageQuery("//psns:Order/psns:OrderID",pathContext) } }; MessageQuerySet GetOrderIDQuerySet = new MessageQuerySet { { "OrderID", new XPathMessageQuery("//ser:guid",pathContext) } }; MessageQuerySet customerQuerySet = new MessageQuerySet { { "CustomerID", new XPathMessageQuery("//psns:GetBaseCost/psns:Customer/psns:CustomerID",pathContext) } }; MessageQuerySet customerIDQuerySet = new MessageQuerySet { { "CustomerID", new XPathMessageQuery("//ser:guid",pathContext) } }; // This will use implicit correlation within the workflow using the WorkflowServiceHost's default CorrelationHandle Receive prescriptionRequest = new Receive { DisplayName = "Request Perscription", OperationName = "GetBaseCost", ServiceContractName = Constants.PharmacyServiceContractName, CanCreateInstance = true, //CorrelatesWith = customerHandle, -- add this line for explicit correlation CorrelatesOn = customerQuerySet, Content = new ReceiveParametersContent { Parameters = { {"Customer",new OutArgument<Customer>(customer)}, {"Drug",new OutArgument<string>(drug)}, } } }; // This will use implicit correlation within the workflow using the WorkflowServiceHost's default CorrelationHandle Receive GetInsurancePaymentPercentageRequest = new Receive { DisplayName = "Get Insurance Coverage", ServiceContractName = Constants.PharmacyServiceContractName, OperationName = "GetInsurancePaymentPercentage", CanCreateInstance = true, //CorrelatesWith = customerHandle, -- add this line for explicit correlation CorrelatesOn = customerIDQuerySet, Content = ReceiveContent.Create(new OutArgument<Guid>()) }; // This will explicitly correlate with the SendReply action after the prescriptionRequest using the OrderID (stored in the orderHandle) Receive GetAdjustedCostRequest = new Receive { DisplayName = "Get Adjusted Cost", OperationName = "GetAdjustedCost", ServiceContractName = Constants.PharmacyServiceContractName, CanCreateInstance = true, CorrelatesOn = GetOrderIDQuerySet, CorrelatesWith = orderHandle, Content = ReceiveContent.Create(new OutArgument<Guid>()) }; Activity PrescriptonWorkflow = new Sequence() { Variables = { customer, order, drug, percentagePaidByInsurance, adjustedCost, customerHandle, orderHandle }, Activities = { new WriteLine { Text = "Beginning Workflow" }, new Parallel { Branches = { new Sequence { Activities = { GetInsurancePaymentPercentageRequest, new Assign<int> { To = new OutArgument<int>( (e) => percentagePaidByInsurance.Get(e) ), Value = new InArgument<int>( (e) => new Random().Next(0,100)) }, new SendReply { DisplayName = "Return Percentage", Request = GetInsurancePaymentPercentageRequest, Content = SendContent.Create(new InArgument<int>((e) => percentagePaidByInsurance.Get(e))) } } }, new Sequence { Activities = { prescriptionRequest, new WriteLine { Text = new InArgument<string>(env => (string.Format("{0}, {1}\t{2}", customer.Get(env).LastName ,customer.Get(env).FirstName,customer.Get(env).CustomerID.ToString()))) }, new Assign<Order> { To = new OutArgument<Order>(order), Value = new InArgument<Order>( (e) => new Order() { CustomerID = customer.Get(e).CustomerID, Drug = drug.Get(e), OrderID = Guid.NewGuid() } ) }, new WriteLine { Text = new InArgument<string>(env => (string.Format("OrderID: {0}", order.Get(env).OrderID.ToString()))) }, new Assign<int> { To = new OutArgument<int>( (e) => order.Get(e).Cost ), Value = new InArgument<int>( (e) => new Random().Next(20,50)) }, new SendReply { DisplayName = "Send Adjusted Cost", Request = prescriptionRequest, // Initialize the orderHandle using the MessageQuerySet to correlate with the final GetAdjustedCost request CorrelationInitializers = { new QueryCorrelationInitializer { CorrelationHandle = orderHandle, MessageQuerySet = GetOrderQuerySet } }, Content = SendContent.Create(new InArgument<Order>((e) => order.Get(e))) } } } } }, new Assign<double> { To = new OutArgument<double>( (e) => adjustedCost.Get(e) ), Value = new InArgument<double>( (e) => order.Get(e).Cost * (100-percentagePaidByInsurance.Get(e)) *.01) }, new WriteLine { Text = new InArgument<string>(env => (string.Format("Base Cost: ${0}", order.Get(env).Cost.ToString()))) }, new WriteLine { Text = new InArgument<string>(env => (string.Format("Insurance Coverage: {0}%", percentagePaidByInsurance.Get(env).ToString()))) }, new WriteLine { Text = new InArgument<string>(env => (string.Format("Adjusted Cost: ${0}", decimal.Round(Convert.ToDecimal(adjustedCost.Get(env)),2)))) }, GetAdjustedCostRequest, new SendReply { Request = GetAdjustedCostRequest, Content = SendContent.Create(new InArgument<double>((e) => adjustedCost.Get(e))) }, new WriteLine { Text = "Workflow Completed" } } }; WorkflowService service = new WorkflowService { Name = "PharmacyService", Body = PrescriptonWorkflow, ConfigurationName = "PharmacyService" }; return service; }