The processing of request messages by the endpoint distributor in its own Runtime is definitely reflected in the execution of corresponding operations. From the service description perspective, the operation is an OperationDescription object. The operations in the server distribution runtime represent a DispatchOperation object. As part of the service description, OperationDescription of all service endpoints is created during ServiceHost creation. When ServiceHost is started normally, these operations describe the final DispatchOperation operation of the conversion component ). The Operations attribute of DispatchRuntime represents all the distribution Operations of the corresponding endpoint.
Directory: i. serialization and deserialization II. Call context initialization III. test parameters IV. Release of service instances v. Transaction VI. Execution of Operations VII. Release of parameters and return values 8. Identity simulation Summary
Next, we also analyze DispatchOperation from an extensible perspective. The following code snippet lists all attributes that can be extended.
1:publicsealedclassDispatchOperation
2:{
3: // serialization and deserialization
4: publicboolDeserializeRequest { get; set; }
5: publicboolSerializeReply { get; set; }
6: publicSynchronizedCollection<FaultContractInfo> FaultContractInfos { get; }
7: publicIDispatchMessageFormatter Formatter { get; set; }
8:
9: // execute context Initialization
10: publicSynchronizedCollection<ICallContextInitializer> CallContextInitializers { get; }
11:
12: // Parameter Test
13: publicSynchronizedCollection<IParameterInspector> ParameterInspectors { get; }
14:
15: // release the service instance
16: publicboolReleaseInstanceAfterCall { get; set; }
17: publicboolReleaseInstanceBeforeCall { get; set; }
18:
19: // transaction
20: publicboolTransactionAutoComplete { get; set; }
21: publicboolTransactionRequired { get; set; }
22:
23: // operation execution
24: publicIOperationInvoker Invoker { get; set; }
25:
26: // release of the parameter/Return Value
27: publicboolAutoDisposeParameters { get; set; }
28:
29: // identity Simulation
30: publicImpersonationOption Impersonation { get; set; }
31:}
I. serialization and deserialization
The execution of the service operations shown in our figure is ultimately reflected in a corresponding operation method for executing the service instance. Parameters need to be passed in to call methods, and parameters are actually based on certain types of objects. However, before that, all service call information is encapsulated in the Message (corresponding to the Message object ). Therefore, the first task before calling a method is to extract the corresponding information from the request message and deserialize it into the input parameters of the method. On the other hand, when the operation method is correctly executed, the execution result is reflected by the return value of the method (or the ref/out parameter. If you want to correctly return the execution results to the client, you need to serialize them into messages.
If you read chapter 5th serialization and data contract in the WCF Technology Analysis (Volume 1), you should be clear that WCF uses a message formatter) to complete serialization and deserialization. For the server, this message formatter is called the DispatchMessageFormatter. It implements a System. ServiceModel. Dispatcher. IDispatchMessageFormatter interface with the following definitions. The two methods are used to deserialize the request message and serialize the Response Message respectively.
1:publicinterfaceIDispatchMessageFormatter
2:{
3: voidDeserializeRequest(Message message, object[] parameters);
4: Message SerializeReply(MessageVersion messageVersion, object[] parameters, objectresult);
5:}
The Formatter attribute of DispatchOperation determines the final message Formatter. By default, WCF uses DataContractSerializer as the message formatter of the serializer. If we want to adopt the traditional XML serialization method, we can also use the message formatter Based on XmlSerializer. The two message formatters can be selected through two corresponding operation actions: DataContractSerializerOperationBehavior and XmlSerializerOperationBehavior.
In addition, serialization-related attributes include DeserializeRequest and SerializeReply. We all know from the semantics that they indicate whether the deserialization of request messages and the serialization of response messages are required. Only define these two attributes for DispatchOperation because serialization and deserialization of messages are not required in any situation. For example, if an operation method has a unique parameter of the Message Type, deserialization of the request Message is not required. Similarly, if the return value (without the ref/out parameter) Type of the operation method is Message, you do not need to serialize the reply Message.
The above describes the serialization and deserialization based on normal service calls. If an exception occurs, we can throw a FaultException <TDetail> exception for the error Contract defined in the operation. To successfully complete the information about the exception message (TDetail type object), you need to determine the necessary information about the error contract in advance. The auxiliary information is transferred to a FaultContractInfo object, And the FaultContractInfos of DispatchOperation indicates the FaultContractInfo set related to all the error contracts of the operation.
Ii. Call context Initialization
Each DispatchOperation has a CallContextInitializer list. Each CallContextInitializer implements the ICallContextInitializer interface with the following definitions.
1:publicinterfaceICallContextInitializer
2:{
3: voidAfterInvoke(objectcorrelationState);
4: objectBeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message);
5:}
Before and after the target operation method is executed, the BeforeInvoke and AfterInvoke methods of each CallContextInitializer in the list are called respectively to initialize and clean up the execution environment of the operation method. The returned value of BeforeInvoke is passed to the AfterInvoke method as the input parameter (correlationState ).
For example, in chapter 1 of WCF Technology Analysis (Volume 1), we use custom ClientMessageInspector and CallContextInitializer to automatically transmit context information from the client to the server. ClientMessageInspector is used to send context information, while CallContextInitializer is used to receive and set context information. In the following section, we will also demonstrate how to use these two components (ClientMessageInspector and CallContextInitializer) to implement another Application Scenario: Make the language culture of the service operation execution thread consistent with that of the customer.
Iii. Parameter Test
The parameter test involves another important component, namely the ParameterInspector, which implements an interface IParameterInspector with the following definitions. Each DispatchOperation has a ParameterInspector list, represented by the ParameterInspectors attribute.
1:publicinterfaceIParameterInspector
2:{
3: voidAfterCall(stringoperationName, object[] outputs, objectreturnValue, objectcorrelationState);
4: objectBeforeCall(stringoperationName, object[] inputs);
5:}
When MessageFormatter deserializes the request message to a parameter for an operation, the BeforeCall method of each ParameterInspector in the list will be executed during the time when the operation method is executed. The operation name and the serialized parameter are passed in this method. On the other hand, from the time when the operation method is successfully executed to the time when MessageFormatter serializes the execution result in the form of a return value (or ref/out parameter) into a reply message, the AfterCall of each ParameterInspector in the list is called. The four input parameters indicate the return values of the operation method, output parameter array, return value, and BeforeCall methods, respectively.
We usually use the custom ParameterInspector method to test the input parameters before the operation is executed, and the return value/output parameters after the operation is executed. For example, Microsoft's Enterprise Library has a Validation Application Block ). This is a very good framework for data entity verification. It allows you to define verification policies for a specific object type. It provides integration for WCF, so that we can apply these independent authentication policies to corresponding operations through declaration or configuration, and finally implement automatic parameter verification. The final verification is the custom ParameterInspector.
4. Release of service instances
When a service instance is released, the two attributes ReleaseInstanceBeforeCall and ReleaseInstanceAfterCall of DispatchOperation are involved. The former indicates to release an existing instance and create a new instance before the service operation. The latter indicates that the service instance will be released after the service operation is executed. To release a service instance, call the ReleaseServiceInstance method of InstanceContext. Generally, this method will call the ReleaseInstance method of InstanceProvider described earlier.
1:publicsealedclassInstanceContext : CommunicationObject, IExtensibleObject<InstanceContext>
2:{
3: // other members
4: publicvoidReleaseServiceInstance();
5:}
6:publicinterfaceIInstanceProvider
7:{
8: // other members
9: voidReleaseInstance(InstanceContext instanceContext, objectinstance);
10:}
These two values can be controlled through OperationBehaviorAttribute. OperationBehaviorAttribute has a ReleaseInstanceMode attribute of the type ReleaseInstanceMode enumeration. We can apply this feature to the corresponding operation method and specify the corresponding instance release mode to control whether the service instance is recycled before or after the operation is called.
1:[AttributeUsage(AttributeTargets.Method)]
2:publicsealedclassOperationBehaviorAttribute : Attribute, IOperationBehavior
3:{
4: // other members
5: publicReleaseInstanceMode ReleaseInstanceMode { get; set; }
6:}
7:publicenumReleaseInstanceMode
8:{
9: None,
10: BeforeCall,
11: AfterCall,
12: BeforeAndAfterCall
13:}
V. Transactions
The two Boolean properties TransactionRequired and TransactionAutoComplete of DispatchOperation are related to transactions. The former indicates whether the current operation should be executed in the transaction, and the latter indicates whether the transaction is automatically committed after the operation is executed. We can control the OperationBehaviorAttribute's TransactionScopeRequired and TransactionAutoComplete attributes.
1:[AttributeUsage(AttributeTargets.Method)]
2:publicsealedclassOperationBehaviorAttribute : Attribute, IOperationBehavior
3:{
4: // other members
5: publicboolTransactionAutoComplete { get; set; }
6: publicboolTransactionScopeRequired { get; set; }
7:}
Vi. Operation execution
The execution of the operation finally falls on a component called the OperationInvoker. OperationInvoker implements the IOperationInvoker interface with the following definitions. The Operation has two different execution methods: synchronous and asynchronous. Operations are implemented in the Invoke method, while InvokeBegin/InvokeEnd is used for asynchronous execution. The input parameters instance and inputs in the method indicate the service instances provided by InstanceProvider and the input parameters generated by deserializing the request message through MessageFormatter. The return values and output parameters (outputs) of Invoke and InvokeEnd indicate the results obtained after the operation is executed.
1:publicinterfaceIOperationInvoker
2:{
3: object[] AllocateInputs();
4: objectInvoke(objectinstance, object[] inputs, outobject[] outputs);
5: IAsyncResult InvokeBegin(objectinstance, object[] inputs, AsyncCallback callback, objectstate);
6: objectInvokeEnd(objectinstance, outobject[] outputs, IAsyncResult result);
7: boolIsSynchronous { get; }
8:}
Whether synchronous or asynchronous operations are performed depends on the read-only attribute IsSynchronous. The AllocateInputs method returns an array with the same number of parameters as the current operation. After MessageFormatter deserializes the request message, it fills the array with the generated parameters. The filled array is finally passed into the Invoke or InvokeBegin method as the input parameter.
WCF provides two Internal (Internal) OperationInvoker to implement synchronous and asynchronous operations, which are SyncMethodInvoker and AsyncMethodInvoker. Their implementation principle is actually very simple, that is, using reflection to call the corresponding operation methods. Specifically, SyncMethodInvoker and AsyncMethodInvoker implement synchronous and asynchronous calls to operations by calling SyncMethod and BeginMethod/EndMethod of the OperationDescription.
1:publicclassOperationDescription
2:{
3: // other members
4: publicMethodInfo BeginMethod { get; set; }
5: publicMethodInfo EndMethod { get; set; }
6: publicMethodInfo SyncMethod { get; set; }
7:}
7. Release of parameters and returned values
When a service operation is successfully executed and the execution result is serialized to the reply message, objects that are used as parameters or return values become "junk objects ". Normally, they are eventually recycled. However, if these objects reference resources to be released, memory leakage may occur.
We should be clear that when designing this type, we generally implement the IDisposable interface and release the resource in the Dispose method. The AutoDisposeParameters attribute of DispatchOperation determines whether to call the Dispose method for parameters and return values that implement the IDisposable interface.
We can control the AutoDisposeParameters attribute value of DispatchOperation through the same name attribute of OperationBehaviorAttribute. By default, the AutoDisposeParameters attribute of DispatchOperation is True. If you want to directly avoid the release operation of parameters and return values, you can use this feature to set the attribute to False.
1:[AttributeUsage(AttributeTargets.Method)]
2:publicsealedclassOperationBehaviorAttribute : Attribute, IOperationBehavior
3:{
4: // other members
5: publicboolAutoDisposeParameters { get; set; }
6:}
8. Identity Simulation
The last Impersonation attribute of the ImpersonationOption type has been described in detail in simulated applications in WCF to indicate whether to perform service operations in the context of the simulated client identity. It corresponds to the same name attribute of the OperationBehaviorAttribute action.
1:[AttributeUsage(AttributeTargets.Method)]
2:publicsealedclassOperationBehaviorAttribute : Attribute, IOperationBehavior
3:{
4: // other members
5: publicImpersonationOption Impersonation { get; set; }
6:}
Summary
For a DispatchOperation object that represents a specific service operation during the distributed operation, its scalable core components include CallContextInitializer, ParameterInspector, DispatchMessageFormatter, and OperationInvoker. They are shown in DispatchOperation.