- Manually route messages
- Endpointdispatcher object and filter
- Route messages to other services
Routing is applicable to scenarios with slightly different processing and monitoring services. Sometimes a message needs to be pushed from one service to another completely different service to process the message. For example, when the client Program Send requests to different internal WCF services, but all these requests actually pass through the front-end service, which is equivalent to the firewall of the WCF Service. The front-end service can run on the computer of the enterprise's peripheral network, while the WCF Service that actually processes requests can host on the protected network inside the Enterprise. The front-end service can implement a routing mechanism to push requests to the real service by checking the message behavior or address. This technology is based on Address Routing . The front-end service can also filter messages. If a message is an illegal request, blocking the message. The effect of message filtering depends on the degree of smart checks implemented on the front-end service. Another similar mechanism is message-based content routing. This technology is based on Content Routing . For example, if you host a commercial service, you may provide different services to users based on the fees paid by users. Advanced users can send requests to high-performance services to quickly obtain responses, while common users can only get responses from services with lower performance. All users use the same client program to send requests to the same front-end service, but the front-end service checks a certain aspect of the message, such as the identity of the user sending the request, then, push the message to the corresponding destination based on the request identity message. Frontend services can also provide other features, such as server Load balancer. Client Requests reach a single front-end service, and the front-end service uses Server Load balancer Algorithm Distribute requests to servers that actually run the WCF Service. WCF provides two main mechanisms for routing. The selection of a mechanism depends on the complexity of the requirement. The routingservice class in the system. servicemodel. Routing namespace provides configuration information for routing messages to other services by checking the message content and message address. Similarly, you can manually route messages based on conditions (such as the load of the current service) If you want to achieve a more dynamic or low-level approach (as required by the Server Load balancer router. Before studying how to use routingservice, it is necessary to explain what happened after the WCF Service received the message from the client and how to use the information to implement a custom routing service. A service that manually routes messages can provide multiple endpoints externally. Each endpoint is configured with the same or different service contracts. When the WCF Service receives a message, it must check the message to determine which server should process the message. You can customize the method for selecting the endpoint of WCF, which provides you with a way to change the WCF route message within the service. Review the channeldispatcer and endpointdispatcher objects in Chapter 11th "write code control configuration and communication, you have learned that the server's WCF runtime creates a channel stack for each different address and bound combination, and then uses this stack to communicate with the service. Each channel Stack has a channeldispatcher object, which corresponds to one or more endpointdispatcher objects. The target of the channeldispatcher object is to determine which endpointdispatcher object should process messages. The role of the endpointdispatcher object is to convert a message request to a method call and call the corresponding method of the service. Each address and bound combination exposed by the service can be shared by multiple endpoints. For example, In the productsservicehost project in Chapter 6 of the productsservicelibrary solution, the following services and endpoints are defined for the Service Contract Products. iproductsservice and products. iproductsservciev2: < Services >
< Service Name = " Products. productsservice " >
< Endpoint Address = " Http: // localhost: 8010/productsservice/service. SVC "
Binding = " Ws2007httpbinding " Bindingconfiguration = "" Name = " Ws2007httpbinding_iproductsservice "
Contract = " Products. iproductsservice " />
< Endpoint Address = " Http: // localhost: 8010/productsservice/service. SVC "
Binding = " Ws2007httpbinding " Bindingconfiguration = "" Name = " Ws2007httpbinding_iproductsservice "
Contract = " Products. iproductsservicev2 " />
</ Service >
</ Services > Note that the preceding configuration defines two endpoints, but they share the same address and binding combination. The only difference is that the service contracts for these two endpoints are different. The preceding configuration will create a single channel stack and a channeldispatcher object during the WCF runtime. However, the channel Stack may be associated with two endpoints. Each service contract uses one service endpoint. Therefore, two endpointdispatcher objects are created for the channel stack during the WCF runtime and added to the endpointdispatcher object set associated with the channeldispatcher object. If the productsservicehost project also provides a TCP endpoint for productsservice, two channel stacks (one for the HTTP endpoint and the other for the TCP endpoint) will be created during the WCF runtime ), each channel uses its own channeldispatcher object. The TCP endpoint has its own endpointdispatcher object. Displays the relationship between endpoints, channel stacks, and distribution objects. When a service receives a message from the channel stack, the channeldispatcher object at the top of the channel stack queries the associated endpointdispatcher object to determine which endpoint can process the message. If no corresponding endpoint is found, an unknownmessagereceived event is triggered during the WCF runtime. How do I specify whether the endpointdispatcher object can process a message? The endpoint distributor provides two attributes addressfilter and contractfilter available for channeldispatcher to query. The addressfilter attribute is an instance variable of the endpointaddresmessagefilter class. The endpointaddressmessagefilter class provides a method named match. This method receives a message object as an input parameter and returns a Boolean value to indicate whether the endpointdispatcher object can recognize the addresses contained in the message header. The contractfilter attribute is an instance variable of the actionmessagefilter class. This class also provides a match method. This method accepts a message object as an input parameter and returns a Boolean value to indicate whether the endpointdispatcher object can process the behaviors contained in the message header. Remember the behavior contained in the message header to identify the method for receiving requests in the service instance called by endpointdispatcher. Internally, the actionmessagefilter object contains an action table, which is used to confirm whether a method matches. When matching, this method is compared one by one with the behavior saved in the table. The result is either to find a matching behavior, or to check all the behaviors but no matching behavior. Both the match methods of the above two filters must return true to the channeldispatcher object that sends messages to them. There may also be more than one endpointdispatcher object that can process messages. In this case, the endpointdispatcher class provides the filterpriority attribute. This attribute returns an integer. An endpointdispatcher object can be compared with another endpointdispatcher object, and a high or low value is returned. If the two matching endpoints return the same priority value, a muitiplefiltermatchesexception exception is thrown during the WCF runtime. Based on the endpoint definition in the service configuration file, each channeldispatcher object creates an endpointaddressfiltermessage and actionmessagefilter object in the WCF runtime. But you can override these filters-this requires you to use a custom address and behavior table to create an object instance and insert it into the WCF runtime before the service is running. This implementation method requires you to create custom behaviors. For more information about creating custom behaviors, see Chapter 11th. By default, endpointdispatcher calls the method corresponding to the behavior in the service contract. However, you can modify the method by which endpointdispatcher processes a request operation: first create a class that implements the idispatchoperationselector interface, and then assign the class to the operationselector attribute of the dispatcherruntime object. Because the dispatcherrumtime attribute of the endpointdispatcher object references the dispatcherruntime object. The interface idispatchoperationselector contains the selectionoperation method. You can use the selectionoperation method to check the message and return the method that the endpointdispatcher object should call. This method is useful if you want to manually control which distribution mechanism to work on. In short, the distribution mechanism provides a highly customized mechanism to determine which endpoint should process messages. You can use it to build services to transparently route messages to other services. Demonstrate the relationship above: it is quite simple to route messages to other services in WCF and construct a service that accepts specific messages and sends messages to another service for processing. What you need to do is to define a front-end service using the image service contract of the target service. The methods defined in the front-end service can perform the necessary preprocessing, such as checking the identity of the user sending the request or checking the sent data, and then pushing these requests to the appropriate target service. However, you can create a common service that can receive any message. In addition, the Service can route messages to other services running on other computers. To build the service, you need to consider more. The following three points are the issues you need to solve:
- service contract. The WCF Service describes the operations that can be performed by the service contract. If a service accepts a message, the message must be recognized by the contractfilter of one or more endpointdispatcher objects, and then pushed to the service that implements the same service contract as the target service. It is very easy to route messages to a single service. When you create a front-end service for multiple different services, the routing messages become uncontrollable quickly, this is because front-end services must implement service contracts for all services.
- message content. This issue is related to the above service contract. When a front-end service must implement a service contract with a large number of services, it must also implement the data contracts used by these services to describe how the data structure is serialized into the message body. Similarly, this will quickly become a time-consuming task.
- message header content. In addition to the message body, a message also contains the message header. These message headers contain information such as encryption keys, transaction identifiers, and other items that control data streams and manage message consistency. The front-end service must carefully manage the information so that the information is transparent to the client sending the request and the service receiving the service processing the request.
Fortunately, there are already many good solutions to solve the above problems. You will study these solutions in subsequent exercises. In these exercises, you will see how to create a simple Server Load balancer router for the shoppingcartservice service. You will run two shoppingcartservice instances, and the Server Load balancer router will distribute requests from clients to the two service instances. Load Balancing Routing implements a simple algorithm that sends alternate requests to the shoppingcartservice. Although the three services in the exercise run on the same computer, it is equally easy to schedule them to run on different machines, and this allows different processors to expand the load. You will get familiar with the shoppingcartservice and modify the service to run in a traditional Internet environment. Exercise: Review continuous shoppingcartservice 1. Use Visual Studio to open the shoppingcart. sln file in the \ WCF \ step by step \ chapter14 \ loadbalancingrouter folder. This solution includes the shoppingcartservice project, shoppingcartservicehost project, and shoppingcartguiclient project in Chapter 7 after modification. 2. Open the ishoppingcartservice. CS file under the shoppingcartservice project and check the file. In chapter 7, the shoppingcartservice implements the additemtocart, removeitemfromcart, getshoppingcart, and checkout operations. 3. Open the shoppingcartservice. CS file and view Code . Note that the Service uses the persession instance mode and marks the durableservice feature. The session status is saved to the wcfpersistence SQL Server database between two calls. 4. Open the programm. CS file of the shoppingcarthost project. This is a service host Program. What it does is to use the servicehost object to start the service and wait for the user to press enter to close the Host Program. 5. Open the app. config file of the shoppingcarthost project. Note that the service host creates an HTTP endpoint using the http: // localhost: 90000/shoppingcartservice. SVC address. In this version of the application, the endpoint is bound with basichttpcontextbinding, which uses the default configuration. In the Internet environment, you are likely to implement transmission-level security to protect the transmission of messages between clients and services. With WCF, you can use the basichttpbinding binding Based on HTTPS to configure transmission-level security. Basichttpcontextbinding binding is a simple extension of the opinion of basichttpbinding. It transmits the ID of the session instance that the client program wants to communicate with as the cookie of the Web Request Header over the network. 6. Open the app. config file of the shoppingcartguiclient project. Verify that the endpoint used by the client program has the same Uri and binding configuration as the service. 7. Run the solution in non-adaptive mode to familiarize you with the customer's programs. In the shopping cart GUI client window, enter the WB-H098 at the product number, and then click Add item. After a short delay, a water bottle is added to the shopping cart and displayed in the client window. Enter the BK-M38S-46 and click the Add item button again and you will find the newly added Silver Mountain bike in the cart. 8. Close the shopping cart GUI client window and close the service host Console window. Up to now, you have a version of shoppingcartservice that can be directly connected by client programs. The next step is to run multiple instances of the service and create another service route message. Based on the load balancing algorithm implemented by the routing service, route the client message to one of these service instances. In the following exercise, you will send requests one by one to two service instances. Exercise: Create the shoppingcartrouter Service 1. Use the WCF Service library template to add a new project to the shoppingcart solution. The project name is shoppingcartservicerouter, which is stored in the \ WCF \ step by step \ chapter14 \ loadbalancingrouter folder. 2. In the shoppingcartservicerouter project, rename service1.cs as router. CS, and rename iservice1.cs as irouter. CS. And allows Visual Studio to update references related to service1. 3. Open the irouter. CS file and add the following code to the top of the file. 4. Delete the comments before the irouter interface and add the following features. 5. Delete the getdata and getdatausingdatacontract operations in the irouter interface. Then add the following operations: Understanding the above Code, rather than viewing service contracts, is the key to understanding how routing works. In the previous discussion, you have learned that when designing a general front-end service to push messages to other services, you need to pay attention to service contracts and message content. A service contract defines operations that can be processed by a service. In a general environment, the WSDL description of an operation consists of the namespace and name attributes. These two attributes come from the namespace and name attributes of the servicecontract feature. They generate a unique identifier together with the operation name, this identifier is what we call action. It defines the request message that the client program should send for the call operation, and also defines the reply behavior in the Response Message returned by the Service. For example, the additemtocart operation in the shoppingcartservice produces the following identifier. If you specify a value for the action attribute explicitly in the operation features during Operation definition, the operation name will be replaced by the value you defined during the WCF runtime. If you specify the value of the action attribute as "*", the WCF runtime will automatically route all messages sent to the operation, regardless of the behavior value specified in the header of the message sent by the client. Internally, the actionmessagefilter object referenced by the contractfilter attribute is replaced with the matchallmessagefilter object during the service's WCF runtime. The match method of the matchallmessagefilter object returns true for all non-null messages sent to this method. Therefore, endpointdispatcher automatically identifies whether it can receive all requests sent to it. In this exercise, when the shoppingcartclient program sends additemtocart, removeitemfromcart, getshoppingcart, and checkout messages to the shoppingcartservicerouter service, the service accepts all these messages and calls the processmessage method. You should also pay attention to the signature of the processmessage method. The client package and pass the operation parameters to the message body of the SOAP message during the WCF runtime. In a general environment, the server's WCF converts the SOAP message body back to a set of parameters that can be passed to the method for implementing service operations. If there is a return value in the method, the server's WCF runtime package the return value to the message and then return the message to the client's WCF runtime, during the running of the WCF client, the message body of the Response Message is converted into The expected type of the client program. The processmessage method is different because the method receives a message object as its input parameter. In Chapter 11th, you have learned that the message class provides the ability to transmit and accept original soap messages. When the server receives a message from the client program during the running of the WCF Service, the whole SOAP message is transmitted to the processmessage method instead of the unwrapped message to obtain the parameter. The processmessage method is used to convert and translate the content of the message object. Similarly, the return value of the processmessage method is also a message object. The processmessage method must create a complete SOAP message containing the expected data format of the client and return the message object. The message header of the response message must contain a replyaction, which corresponds to the replyaction expected during the client's WCF runtime. Generally, a replyaction is added based on the service and operation name during the server-side WCF runtime. For example, the additemtocart Response Message of the client program returned by the shoppingcartservice will generate the following identifier: Response "*". In this case, you are expected to provide the appropriate replyaction in the Code during the server's WCF runtime, then, the replyaction is added to the message header when you create a response message during the WCF runtime. In this case, you do not change the replyaction returned from the shoppingcartservice and then upload it back to the client program. 6. Remove the compositetype class, including the datacontract feature in the irouter. CS file. 7. Open the router. CS file and add the following declaration to the file header. 8. Delete the comments of the router class, the getdata method and the getdatausingdatacontract method. 9. Adding the servicebehavior feature to the router class will provide the Implementation of processmessage. If you are familiar with the SOAP protocol, you will notice that you can include information that the receiving service can recognize and process in the message header. In this exercise, the shoppingcartservicerouter service does not process messages by itself. It simply pushes messages to an instance of the shoppingcartservcie service. Therefore, it does not need to check or understand the message header and push them to the service instance without any changes. Set the validatemustunderstand attribute of the servicebehavior feature class to false to disable the service for any identification or verification of message header information. 10. adding the following private variables to the shoppingcartservicerouter service of the router class will act as a client program to access two shoppingcartservcie service instances, send messages to each instance, and wait for a response. The features of the processmessage method require that the underlying technology described in Chapter 11th be used instead of connecting to the shoppingcartservice through a proxy object. You will use the ichannelfactory object to create a channel factory that loves you, which is based on irequestchannel to open a channel with each instance of shoppingcartservice. The endpointaddress object specifies the URI of each shoppingcartservice instance. In the subsequent steps, you will configure the shoppingcartservicehost program to use these two addresses to run two shoppingcartservice instances. The processmessage method uses the routebalancer variable to determine which instance of shoppingcartservice to send messages. 11. Add the following code to the constructor of the router class. The processmessage method will use a channelfactory object to open a channel with an appropriate shoppingcartservice instance. The creation and destruction of channelfactory objects are very resource-consuming, and the scenario in our practice is a single service, that is, all requests will reuse the same channelfactory object; therefore, creating a channelfactory object in the static method constructor ensures that this object is created only once. In addition, note that the channelfactory object uses the basichttpcontextbinding object when it is created. The binding matches the HTTP address and the needs of two shoppingcartservice instances (both services are continuity services and the context information is transmitted through the header information of the SOAP message ). 12. Add the processmessage Method to the router class. This method contains multiple console. writeline statements, which allow you to track service running in the console window of the server. The IF statement in the try code snippet implements the load balancing algorithm. If the routebalencer variable value is an even number, the above method creates a channel and pushes the request to address1 (https: // localhost: 9010/shoppingcartservice. SVC); otherwise, the above method creates a channel for address2. The preceding method then adds the routebalancer variable value (+ 1 ). In this way, the processmessage method sends all requests to the two instances of the shoppingcartservice alternately. The preceding method has a subtle note, that is, the context Protocol implemented by binding. Remember that when you use wshttpcontextbinding, basichttpcontextbinding, or nettcpcontextbinding, the message can contain context information. Persistent services use the context information to associate client requests and send them directly to appropriate sessions. By default, the channel that receives messages caches the context information internally. The same context information is also observed when other services are called. However, the received message also contains the same context message. Therefore, when a message is pushed to a service instance, the same context message is sent twice, when a message is sent by a route, an error occurs in the service. The solution is to remove the context information of the stack message before pushing the message, which can be completed through the message. properties. Remove ("contextmessageproperty") statement. The request method of the irequestchannel class sends the message object to the target service through the channel. The returned value is another message object that contains the service response. Then the processmessage method transmits the message to the Client Program (no changes are made to the message ). Remember that the client message sending object may contain security or other information. Unlike context data, the processmessage method does not check or modify the information, because the target service does not care whether the message is pushed by the shoppingcartservicerouter service. Similarly, the processmessage method does not change the response message, and the route directly transmits the Response Message to the client program. However, this does not prevent you from adding code before passing the message to modify the content of the request message or response message. This brings security considerations. Therefore, you should ensure that the shoppingcartservicerouter service should be deployed in a secure environment. In the production environment, you generally use the iis host routing service because IIS is easy for external access. To simplify the process, we will use the Host Program of the host shoppingcartservice to host the shoppingcartservicerouterservice. You will modify the host configuration file to provide two endpoints for the shoppingcartservice, and the two endpoints will officially be the endpoints expected by the shoppingcartservicerouterservice service. Exercise: configure the shoppingcarthost program to host the shoppingcartrouterservcie service. 1. Use the WCF Service configuration management tool to edit the app. config file under the shoppingcarthost project. 2. On the configuration panel, right-click the service folder and choose create service. In the right-side pane, enter shoppingcartservicerouter. router3. on the configuration panel, right-click the shoppingcartservicerouter. Router service endpoint folder and choose create service endpoint. On the service endpoint panel, specify the properties of the endpoint according to the values in the following table.
|Http: // localhost: 9000/shoppingcartservice. SVC
Pay attention to the routing service address and shoppingcartservice address, so that the existing client will directly connect to the routing service without updating the configuration. 4. On the configuration panel, select the service folder, expand shoppingcartservice. shoppingcartserviceimpl service, expand the endpoint folder, and click untitled endpoint. On the service endpoint panel, set the endpoint name to shoppingcartservicehttpendpoint1 and change the address to http: // localhost: 9010/shoppingcartservice. svc5. on the configuration panel, go to shoppingcartservcie. right-click the shoppingcartserviceimpl service endpoint and choose create service endpoint to add the second service endpoint. Specify the properties of the endpoint according to the values in the following table.
| attribute value
| http: // localhost: 9020/shoppingcartservice. SVC
| shoppingcartservcie. ishoppingcartservice
6. Save the configuration file and exit the WCF Service configuration management tool. 7. In the solution window, add shoppingcarthost reference to the shoppingcartservicerouter project. 8. Open the shoppingcarthost project's programm. CS file, and add the following code (in the red box). The preceding statement creates a new servicehost object for the shoppingcartservicerouter service. 9. The shoppingcarthost program uses ports 9010 and 9020 as the endpoint of the shoppingcartservice. You are not allowed to keep these two ports so that the shoppingcarthost program can access these two ports. Run the visual Command Prompt window as an administrator and enter the following command: 10. close the Visual Studio Command Prompt window and return to Visual Studio exercise: Test shoppingcartrouter Service 1. run the solution in non-adaptive mode. Enter the PU-M044 in the product code section of the shoppingcartgui client window, and then click the Add button. This adds a water bottle to the shopping cart. Then add another product WB-H098; then click the settlement button. The client program should work the same way as the previous exercises. However, if you check the service console window, you will see that the routing service pushes the request message in order to two instances of the shoppingcartservice service. The service endpoint address is replaced between 9020 and 9010. The two-day request message is pushed to two different service instances by routing service. 2. Close the shopping cartgui window, and press enter in the service console window to stop the service. Refer to the msdn routing service http://msdn.microsoft.com/zh-cn/library/ee517421.aspx