Example #1
0
        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;
 }
Example #3
0
        // 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;
        }
Example #6
0
        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));
            }
        }
Example #7
0
        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);
                }
            }
        }
Example #9
0
        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;
        }