WCF服务端运行时架构体系详解[续篇]
终结点分发器在自己的运行时中对请求消息的处理最终肯定体现在相应操作的执行。如果从服务描述的角度来看,操作是一个OperationDescription对象。而服务端分发运行时中的操作则代表的是一个DispatchOperation对象。作为服务描述的一部分,服务所有终结点的所有操作描述(OperationDescription)在ServiceHost创建过程中被创建。而当ServiceHost被正常开始时,这些操作描述最终转换成分发操作(DispatchOperation)。而DispatchRuntime的Operations属性代表了对应终结点的所有分发操作。
目录:一、序列化与反序列二、调用上下文初始化三、参数的检验四、服务实例的释放五、事务六、操作的执行七、参数和返回值的释放八、身份模拟总结
接下来,我们同样从可扩展的角度来分析DispatchOperation,下面的代码片断列出了所有可供扩展的属性。
1:publicsealedclassDispatchOperation2:{3: //序列化与反序列化4: publicboolDeserializeRequest { get; set; }5: publicboolSerializeReply { get; set; }6: publicSynchronizedCollection<FaultContractInfo> FaultContractInfos { get; }7: publicIDispatchMessageFormatter Formatter { get; set; }8:9: //执行上下文初始化10: publicSynchronizedCollection<ICallContextInitializer> CallContextInitializers { get; }11:12: //参数检验13: publicSynchronizedCollection<IParameterInspector> ParameterInspectors { get; }14:15: //服务实例释放16: publicboolReleaseInstanceAfterCall { get; set; }17: publicboolReleaseInstanceBeforeCall { get; set; }18:19: //事务20: publicboolTransactionAutoComplete { get; set; }21: publicboolTransactionRequired { get; set; }22:23: //操作执行24: publicIOperationInvoker Invoker { get; set; }25:26: //参数/返回值的释放27: publicboolAutoDisposeParameters { get; set; }28:29: //身份模拟30: publicImpersonationOption Impersonation { get; set; }31:}
一、序列化与反序列
我们所示的服务操作的执行最终体现在执行服务实例的某个相应的操作方法。而调用方法需要传入参数,而参数是一个个实实在在的基于某种类型的对象。但是在这之前,所有的服务调用信息被封装在消息中(对应于Message对象)。那么,在真正执行方法调用之前首要的任务就是从请求消息中提取相应的信息并将其反序列化成方法的输入参数。在另一方面,当操作方法被正确执行后,执行的结果通过方法的返回值(或者ref/out参数)来体现。如果要将执行结果正确地回复给客户端,需要将它们进行序列化成消息。
如果你阅读了《WCF技术剖析(卷1)》第5章《序列化与数据契约》,你应该很清楚WCF通过一个被称为消息格式化器(MessageFormatter)组件来完成序列化和反序列化工作。对于服务端来说,这个消息格式化器被称为分发消息格式化器(DispatchMessageFormatter),它实现了一个具有如下定义的System.ServiceModel.Dispatcher.IDispatchMessageFormatter接口。两个方法分别用于对请求消息的反序列化和对回复消息的序列化。
1:publicinte易做图ceIDispatchMessageFormatter2:{3: voidDeserializeRequest(Message message, object[] parameters);4: Message SerializeReply(MessageVersion messageVersion, object[] parameters, objectresult);5:}DispatchOperation的Formatter属性决定以最终采用的消息格式化器。在默认的情况下,WCF利用DataContractSerializer作为序列化器的消息格式化器。如果我们希望采用传统的XML序列化方式,我们也可以使用基于XmlSerializer作为序列化器的消息格式化器。两种不同消息格式化器的选择可以通过如下两个对应的操作行为来实现:DataContractSerializerOperationBehavior和XmlSerializerOperationBehavior。
此外,与序列化相关的还具有两个布尔类型的属性DeserializeRequest和SerializeReply。从语义上我们都知道,它们分别表示是否需要进行请求消息的反序列化和回复消息的序列化。只所有要为DispatchOperation定义如此两个属性,原因在于消息的序列化反序列化并不是在任何情况下都是需要的。比如,如果操作方法具有一个唯一的类型为Message的参数,那么对请求消息的反序列化是不需要的。同理,如果操作方法的返回值(并且没有ref/out参数)类型为Message,那么就不需要进行对回复消息的序列化。
上面介绍的都是基于正常服务调用情况下的序列化和反序列化。如果异常出现,我们可以针对定义在操作上的错误契约(Fault Contract)抛出FaultException<TDetail>异常。为了顺利完成针对该异常消息信息(TDetail类型对象),需要预先确定必要的错误契约相关的信息。这些辅助性信息被风转在一个FaultContractInfo对象中,而DispatchOperation的FaultContractInfos表示与该操作所有错误契约相关的FaultContractInfo集合。
二、调用上下文初始化
每个DispatchOperation都有一个以属性CallContextInitializers表示的调用上下文初始化器(CallContextInitializer)列表。每个CallContextInitializer都实现了具有如下定义的接口ICallContextInitializer。
1:publicinte易做图ceICallContextInitializer2:{3: voidAfterInvoke(objectcorrelationState);4: objectBeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message);5:}当目标操作方法执行前后,列表中每个CallContextInitializer的BeforeInvoke和AfterInvoke方法分别被调用,用以实现针对操作方法执行环境的初始化和清理工作。其中BeforeInvoke的返回值会被传到AfterInvoke方法中作为输入参数(correlationState)。
举个例子,在《WCF技术剖析(卷1)》的第10章,我分别采用自定义ClientMessageInspector和CallContextInitializer实现了上下文信息从客户端到服务端的自动传播。其中ClientMessageInspector用于上下文信息的发送,而CallContextInitializer用于上下文信息的接收和设置。在接下来的部分,我们还将演示如何利用这两个组件(ClientMessageInspector和CallContextInitializer)实现另一个应用场景:让服务操作执行线程的语言文化与客户但保持一致。
三、参数的检验
参数的检验涉及到另一个重要的组件,即参数检验器(ParameterInspector),它实现了一个具有如下定义的接口IParameterInspector。每个DispatchOperation具有一个ParameterInspector列表,通过属性ParameterInspectors表示。
1:publicinte易做图ceIParameterInspector2:{3: voidAfterCall(stringoperationName, object[] outputs, objectreturnValue, objectcorrelationState);4: objectBeforeCall(stringoperationName, object[] inputs);5:}在当MessageFormatter将请求消息反序列化为针对某个操作的参数,到操作方法被执行这段时间内,列表中的每个ParameterInspector的BeforeCall方易做图被执行。操作名称和分序列化后的参数会被传入这个方法。另一方面,从操作方法执行成功,到MessageFormatter将以返回值(或者ref/out参数)形式体现的执行结果序列化成回复消息的这段时间内,列表中的每个ParameterInspector的AfterCall会被调用。而四个输入参数分别表示操作方法、输出参数数组、返回值和BeforeCall方法的返回值。
我们通常通过自定义ParameterInspector的方式实现操作执行前对输入参数的
补充:Web开发 , ASP.Net ,