Summary
The WCF Service distributor can translate and check the messages before passing messages to the service instance method or after receiving the service response message. If you need to implement the Message check function, you must first customize the Service Behavior of the check message, then, the service behavior is embedded into the Code through hard encoding or the WCF Service behavior is extended, and the message check function is configured through the configuration file.
Check messages
An interesting feature of the WCF Service model is to translate messages before sending messages to the service method. After leaving the service method, you can translate messages again before sending a message back to the client. Message translation allows you to check messages when receiving and sending messages. You can also modify a message before the service instance object method processes the message or before sending a Response Message to the client. Although you must be careful when using it to avoid security risks or vulnerabilities in your system, Message check is still a very useful technology.
You can create a message Checker to translate messages. That is, you can create a class that implements the IDispatchMessageInspector interface and then define a behavior to insert the object to the WCF infrastructure; this action determines the range of message translation. If you specify a message to be translated as a service action, all messages sent to the service will be translated. You can also specify a message to be translated as an operation behavior, endpoint behavior, or contract behavior. Correspondingly, messages that have been operated, terminated, and contracted will be translated.
You can check messages in a client program or service. In the following exercise, you will see how to create and integrate a message Checker to the server's WCF runtime distribution mechanism. If the service receives a message, the message checker displays the received message. If you want to check messages on the client, you need to implement the IClientMessageInspector interface.
Create a message checker for the ShippingCartService
1. In the solution window of Visual Studio, select the ShoppingCartService project. In the project menu, select Add a new class file and name it ShoppingCartInspector. cs.
2. In the ShoppingCartInspector. cs file, add the following statement
1usingSystem. ServiceModel. Dispatcher;
2usingSystem. ServiceModel. Description;
3. Modify the ShoppingCartInspector class definition to implement the IDispatchMessageInspector interface.
1 publicclassShoppingCartInspector: IDispatchMessageInspector
2 {
3}
The IDispatchMessageInspector interface defines two methods. You can use these two methods to view and modify the messages that enter and exit the service.
4. Right-click the IDispatchMessageInspector and point to the Implementation interface. Visual Studio automatically generates two methods for the IDispatchMessageInspector interface. The name is AfterReceiveRequest. This method is called before the service method is accessed. The other name is BeforeSendReply. This method is called before the service method ends. Note that the first parameter of both methods is of the Message object type. The value of this parameter is the message object just received or to be sent. You can modify the content of the message object in the method. all the changes you make to the object will be passed to the service or returned to the client, it depends on whether the message is a request message sent by the client or a Response Message of the service. For this reason, you should be extremely careful when modifying the message. do not modify the message on the contrary.
5. Modify the AfterReceiveRequest method generated by Visual Studio.
1 publicobjectAfterReceiveRequest (refSystem. ServiceModel. Channels. Message request,
2 System. ServiceModel. IClientChannel channel, System. ServiceModel. InstanceContext instanceContext)
3 {
4 Console. WriteLine ("Message received ed: {0} \ n {1} \ n", request. Headers. Action, request. ToString ());
5 returnnull;
6}
The first line of code displays the message behavior and content. In some cases, messages associated with the AfterReceiveRequest method and messages of the BeforeSendReply method are very useful. If you view the BeforeSendReply method, you can see that the second parameter of this method is correlationState. If you need to associate request and response messages, you can create a unique identifier in the AfterReveiveRequest method and return a value change. The same identifier will be passed as a parameter to the BeforeSendReplyMethod method during the WCF runtime. In the current exercise, you have not associated any request or reply message, so the AfterReceiveRequest method returns null.
6. modify the content of the BeforeSendReply method generated by Visual Studio.
1 publicvoidBeforeSendReply (refSystem. ServiceModel. Channels. Message reply, objectcorrelationState)
2 {
3 Console. WriteLine ("Message sent: {0} \ n {1} \ n", reply. Headers. Action, reply. ToString ());
4}
7. regenerate the ShoppingCartService Solution
Create custom Behavior
With service behavior, you can integrate the behavior implemented by ShoppingCartInspector into the WCF runtime. However, WCF does not provide the built-in "IntegrateShoppingCartInspector" service behavior. Fortunately, it is not difficult to create a class that implements the IServieBehavior interface to implement integrated service behavior.
The IServiceBehavor interface defines three methods. The implementation class must implement these three methods to act as a Service Behavior in the WCF infrastructure. The three methods are as follows:
- AddingBindingParametersSome actions can receive additional data items as parameters and pass them to the binding element. administrators or developers can provide this information in BindingParameterCollection and pass the information to this method. The AddingBindingParameters method is called once for every URI that listens to the service when running WCF.
- ApplyDispatcherBehaviorIn this way, you can modify the behavior of the Service hosted by the ServiceHost object. The ServiceHost object is passed in as the second parameter of this method. Tasks that can be executed using this method include adding custom error handling or message check objects.
- ValidateTo verify whether the service meets your defined requirements. For example, you can check the first parameter of the method (the input service description object). If the contract of the service is inconsistent with the Expected One, you can reject and throw an exception.
If you need to implement an operation behavior, service endpoint behavior, or contract behavior, you need to implement the IOperationBehavior, IEndpointBehavior, and IContractBehavior interfaces. These interfaces are very similar to IServiceBehavior. Both of them expose the AddingBindingParameters, ApplyDispatcherBehavior, and Validate methods. Although the parameters received by these methods are different (because these interfaces direct to operations, server points, and contracts respectively), they all have the same purpose. In addition, these three interfaces provide a method named ApplyClientBehavior. This method receives a parameter named ClientRuntime, which is the client's WCF runtime object. You can modify the properties of this object to configure the running mode of the client during runtime. When you need to check or manage messages sent by the client and interfaces, you can also insert a message Checker to the client runtime.
In the following exercise, you will implement an IServiceBehavir interface and create a service behavior that can be used to add the message Checker to ShoppingCartService.
Creates a service behavior for the ShoppingCartService.
1. In the ShoppingCartInspector. cs file, add a public class named ShoppingCartBehavior, which implements the IServiceBehavior Interface
PublicclassShoppingCartBehavior: IServiceBehavior
2. Right-click IServiceBehavior and point to implementation interface. Visual Studio automatically generates the AddBindingParameters, ApplyDispatcherBehavior, and Validate Methods
3. comment out the throw statements in the AddingBindingParameters and Validate methods.
4. Modify the ApplyDispatcherBehavior Method
1 publicvoidApplyDispatchBehavior (ServiceDescription serviceDescription,
2 System. ServiceModel. ServiceHostBase serviceHostBase)
3 {
4 foreach (ChannelDispatcher channelDispatcher inserviceHostBase. ChannelDispatchers)
5 {
6 foreach (EndpointDispatcher endpointDispatcher inchannelDispatcher. Endpoints)
7 {
8 endpointDispatcher. DispatchRuntime. MessageInspectors. Add (newShoppingCartInspector ());
9}
10}
11}
The above code first iterates ChannelDispatchers; then iterates the EndpointDispatcher of each ChannelDispatcher; then adds the ShoppingCartInspector object to each EndpointDispatcher. Then, when an EndpointDispatcher object distributes a service method or a service method and returns to the EndpointDispatcher object, messages are transmitted through the ShoppingCartInspector object.
5. Open the Programm. cs file and modify the main method to add the service behavior implemented by ShoppingCartServiceBehavior when ShoppingCartService is running.
1 staticvoidMain (string [] args)
2 {
3...
4 ServiceHost host = newServiceHost (typeof (ShoppingCartService. ShoppingCartService ));
5 host. AddServiceEndpoint (typeof (ShoppingCartService. IShoppingCartService), customBinding, "net. tcp: // localhost: 8090/ShoppingCartService ");
6
7 host. Description. Behaviors. Add (newShoppingCartService. ShoppingCartBehavior ());
8
9 host. Open ();
10...
11}
6. Run the solution in non-adaptive mode. After the service is started, press ENTER in the console window.
The client application runs as before (but this time it is a little slow ). The server console displays the received and sent SOAP messages. The results are shown in:
7. Press ENTER in the console window to close the client program. In the console window of the Host Program, press ENTER to stop the service.
Define behavior extension elements
In the above exercise, by adding this Behavior to the Behavior set of the Description attribute of the ServiceHost object, you hardcoded the ShoppingCartBehavior Behavior to the service host Program. However, this behavior is an example of unimportant functional behavior. Generally, such behavior should be enabled or disabled by the Administrator in the configuration file.
To support configuration behavior in the configuration file, you must provide a behavior extension element. The behavior extension element is a class. When a service is started during the WCF runtime and the configuration file is read, an action is configured using the extension element class. The behavior extension element allows the current type to be implemented during the WCF operation, and then instantiates the type. If necessary, configure the attributes corresponding to the object.
The simplest way to implement behavior extension elements is to extend the BehaviorExtensionElement class in the System. ServiceModel. Configuration namespace. The BehaviorExtensionElement class is an abstract class that provides most of the required functions. You can override these methods when necessary. In an extension class, you must provide an attribute named BehaviorType (which returns the type of the row) and a CreateBehavior method (which instantiates this behavior ).
In the following exercise, you will create a behavior extension element named ShoppingCartBehaviorExtensionElement, and then update the ShoppingCartService configuration file to reference this behavior extension element.
Creates a behavior extension element for ShoppingCartBehavior Behavior
1. Add System. Configuration reference to ShoppingCartService project in Visual Studio
2. Return to the ShoppingCartInspector. cs file and add the following using statement
UsingSystem. ServiceModel. Configuration;
3. Add a public class named ShoppingCartBehaviorExtensionElement, which inherits the BehaviorExtensionElement class.
4. In ShoppingCartBehaviorExtensionElement, rewrite the BehaviorType attribute.
1 publicoverrideType BehaviorType
2 {
3 get {returntypeof (ShoppingCartBehavior );}
4}
5. In ShoppingCartBehaviorExtensionElement, override the CreateBehavior method.
ProtectedoverrideobjectCreateBehavior ()
{
ReturnnewShoppingCartBehavior ();
}
6. regenerate the solution
The next step is to remove the hardcoded ShoppingCartBehavior behavior from the ShoppingCartHost program, and then add the extended behavior through the configuration file. You will create an anonymous service behavior in the configuration file, which will be automatically obtained and referenced by the service host Program.
Configure ShoppingCartService to use ShoppingCartBehavior
1. Open the program. cs file under the ShoppingCartHost Project
2. Modify the main method and comment out the hard-coded ShoppingCartBehavior behavior.
1 staticvoidMain (string [] args)
2 {
3...
4 ServiceHost host = newServiceHost (typeof (ShoppingCartService. ShoppingCartService ));
5 host. AddServiceEndpoint (typeof (ShoppingCartService. IShoppingCartService), customBinding, "net. tcp: // localhost: 8090/ShoppingCartService ");
6
7 // host. Description. Behaviors. Add (new ShoppingCartService. ShoppingCartBehavior ());
8
9 host. Open ();
10...
11}
3. Use the service configuration management tool to open app. config
4. In the configuration panel, expand the Advanced folder, expand the extension node, and then click behavior element extension.
5. Click "CREATE" at the bottom of the behavior Element Extension panel. In the edit extension configuration element dialog box, enter messageInspector.
6. select the type button and go to * \ WCF \ Step. by. shoppingCartService under Step \ Solutions \ Chapter11 \ CustomBinding \ ShoppingCartHost \ bin \ Debug. dll file, and then click open. You can find that the ShoppingCartBehaviorExtensionElement type will be automatically filled. Click Open.
7. Click "OK" in the edit extension configuration element dialog box. The extension element messageInspector will be added to the behavior Element Extension list.
8. On the "advanced" service behavior node, click "create service behavior configuration.
9. In the right panel, clear the Name attribute value of the action. Click "add" in the lower right corner, select "messageInspector", and click "OK. As shown in figure:
10. Save the configuration file and exit the service configuration management tool.
11. In Visual Studio, open app. config. The content should be as follows:
1 <? Xml version = "1.0" encoding = "UTF-8"?>
2 <configuration>
3 <connectionStrings>
4 <add name = "AdventureWorksEntities" connectionString = "metadata = res: // */ProductsModel. csdl | res: // */ProductsModel. ssdl | res: // */ProductsModel. msl; provider = System. data. sqlClient; provider connection string = & quot; data source = localhost; initial catalog = AdventureWorks; integrated security = False; user id = ap_wcf; password = ap_wcf; multipleactiveresultsets = True; app = EntityFramework & quot; "providerName =" System. data. entityClient "/>
5 </connectionStrings>
6
7 <system. serviceModel>
8 <behaviors>
9 <serviceBehaviors>
10 <behavior>
11 <messageInspector/>
12 </behavior>
13 </serviceBehaviors>
14 </behaviors>
15 <extensions>
16 <behaviorExtensions>
17 <add name = "messageInspector" type = "ShoppingCartService. ShoppingCartBehaviorExtensionElement, ShoppingCartService, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null"/>
18 </behaviorExtensions>
19 </extensions>
20 </system. serviceModel>
21 </configuration>
12. Run the solution in non-adaptive mode. On the ShoppingCartClient console, press ENTER. The client program and service will be consistent with the results of the previous exercise. The messages output by the ShoppingCartInspector object are displayed in the host service console window.
13. Press ENTER in the console window to close the client program. In the console window of the Host Program, press ENTER to stop the service.
Through running results, you can easily verify that the anonymous behavior ShoppingCartInspector is automatically recognized by the ShoppingCartService from the configuration file. In this example, we use anonymous service behavior. What is the difference between anonymous service behavior and naming service behavior? Naming Service behavior is used only when the service is defined in the configuration file. If code is used to define the service, we need to use anonymous service behavior (for example, in this example ). If you use the code to define the service, but set the service behavior with the name, the messages through the ShoppingCartInspector object will not be displayed in the ShoppingCartHost Console window.