QueryStringFormatter 示例演示了如何使用 Windows Communication Foundation(WCF)扩展点来处理与 WCF 预期格式不同的消息数据。 默认情况下,WCF 格式化程序要求在元素下 soap:body
包含方法参数。 但是,此示例演示如何实现一个自定义操作格式化程序,用于分析 HTTP GET 查询字符串中的参数数据并使用该数据调用方法。
此示例基于名为Getting Started的指南,并实现ICalculator
服务协定。 它展示了如何将加法、减法、乘法和除法消息更改为使用 HTTP GET 进行客户端到服务器的请求,以及使用 POX 消息的 HTTP POST 进行服务器到客户端的响应。
为此,此示例提供以下内容:
QueryStringFormatter
,它分别为客户端和服务器实现 IClientMessageFormatter 和 IDispatchMessageFormatter,并处理查询字符串中的数据。UriOperationSelector
,它在服务器上实现了 IDispatchOperationSelector,根据 GET 请求中的操作名称执行操作调度。EnableHttpGetRequestsBehavior
终结点行为(和对应的配置),它向运行库中添加必要的操作选择器。演示如何将新的操作格式化程序插入到运行时中。
在此示例中,客户端和服务都是控制台应用程序(.exe)。
注释
本示例的设置过程和生成说明位于本主题末尾。
关键概念
QueryStringFormatter
-作格式化程序是 WCF 中的组件,负责将消息转换为参数对象的数组,并将参数对象的数组转换为消息。 这是通过在客户端使用 IClientMessageFormatter 接口以及在服务器上使用 IDispatchMessageFormatter 接口来完成的。 这些接口使用户能够从 Serialize
和 Deserialize
方法获取请求和响应消息。
在此示例中, QueryStringFormatter
实现这两个接口,并在客户端和服务器上实现。
请求:
此示例使用 TypeConverter 类将请求消息中的参数数据转换为字符串和从字符串转换参数数据。 如果某个特定类型的 TypeConverter 不可用,示例格式化程序将引发异常。
在客户端的
IClientMessageFormatter.SerializeRequest
方法中,格式化程序创建一个带有适当 To 地址的 URI,并将操作名称追加为后缀。 此名称用于调度给服务器上的相应操作。 然后,它将参数对象数组中的参数数据使用参数名称和由 TypeConverter 类转换的值序列化为 URI 查询字符串。 然后,将To和Via属性设置为此 URI。 MessageProperties 是通过 Properties 属性访问的。在服务器上的
IDispatchMessageFormatter.DeserializeRequest
方法中,格式化器从接收的请求消息属性中检索Via
URI。 它将 URI 查询字符串中的名称值对分析为参数名称和值,并使用参数名称和值填充传入方法的参数数组。 请注意,操作调度已经发生,因此在此方法中忽略操作名称后缀。
响应:
- 在此示例中,HTTP GET 仅用于请求。 格式化程序将响应发送到本来用于生成 XML 消息的原始格式化程序。 此示例的目标之一是演示如何实现此类委派格式化程序。
UriPathSuffixOperationSelector 类
该 IDispatchOperationSelector 接口使用户能够实现自定义逻辑,以确定应如何调度特定消息。
在此示例中,UriPathSuffixOperationSelector
必须在服务器上实现以选择适当的操作,因为操作名称包含在 HTTP GET URI 中,而不是消息中的操作头。 此示例设置为仅允许不区分大小写的操作名称。
该方法 SelectOperation
接收传入的消息,并在消息属性中查找 Via
URI。 它从 URI 中提取操作名称后缀,查找内部表以获取消息应该调度到的操作名称,并返回该操作名称。
EnableHttpGetRequestsBehavior 类
UriPathSuffixOperationSelector
组件可以通过编程方式或通过终结点行为进行设置。 此示例实现 EnableHttpGetRequestsBehavior
在服务的应用程序配置文件中指定的行为。
在服务器上:
OperationSelector 设置为 IDispatchOperationSelector 实现。
默认情况下,WCF 使用完全匹配的地址筛选器。 传入消息上的 URI 包含操作名称后缀,后跟包含参数数据的查询字符串,因此终结点行为也会将地址筛选器更改为前缀匹配筛选器。 它使用 WCFPrefixEndpointAddressMessageFilter 实现此目的。
安装操作格式化程序
指定格式化程序的操作行为是唯一的。 默认情况下,每个操作默认都会实现这种行为,以便创建必要的操作格式器。 但是,这些行为像是另一种操作行为,它们不能由任何其他属性标识。 若要安装替换行为,实现必须查找 WCF 类型加载程序默认安装的特定格式化程序行为,并替换它或添加兼容行为,以便在默认行为之后运行。
可以在调用 CommunicationObject.Open 之前通过编程方式设置这些操作格式化程序的行为,或者指定一个在默认行为之后执行的操作行为。 但是,由于行为模型不允许行为替换其他行为或修改描述树,因此无法通过终结点行为轻松配置它(也无法通过配置实现)。
在客户端上:
必须对IClientMessageFormatter进行实现,使其可以将请求转换为 HTTP GET 请求,并将响应委托给原始格式化程序。 这是通过调用EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior
帮助程序方法完成的。
必须在调用 CreateChannel
之前执行此作。
void ReplaceFormatterBehavior(OperationDescription operationDescription, EndpointAddress address)
{
// Remove the DataContract behavior if it is present.
IOperationBehavior formatterBehavior = operationDescription.Behaviors.Remove<DataContractSerializerOperationBehavior>();
if (formatterBehavior == null)
{
// Remove the XmlSerializer behavior if it is present.
formatterBehavior = operationDescription.Behaviors.Remove<XmlSerializerOperationBehavior>();
...
}
// Remember what the innerFormatterBehavior was.
DelegatingFormatterBehavior delegatingFormatterBehavior = new DelegatingFormatterBehavior(address);
delegatingFormatterBehavior.InnerFormatterBehavior = formatterBehavior;
operationDescription.Behaviors.Add(delegatingFormatterBehavior);
}
在服务器上:
IDispatchMessageFormatter必须实现该接口,以便它可以读取 HTTP GET 请求并委托给原始格式化程序以编写响应。 这是通过调用与客户端相同的
EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior
帮助程序方法完成的(请参阅前面的代码示例)。必须在调用Open之前完成此操作。 在此示例中,我们将演示如何在调用 Open之前手动修改格式化程序。 实现相同目的的另一种方法是从 ServiceHost 派生一个类,该类在打开之前调用
EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior
(请查看托管文档和示例)。
用户体验
在服务器上:
服务器
ICalculator
实现不需要更改。服务的 App.config 必须使用自定义的 POX 绑定来将
messageVersion
元素的textMessageEncoding
属性设置为None
。<bindings> <customBinding> <binding name="poxBinding"> <textMessageEncoding messageVersion="None" /> <httpTransport /> </binding> </customBinding> </bindings>
服务的 App.config 还必须指定自定义
EnableHttpGetRequestsBehavior
(通过将其添加到行为扩展部分并使用它来实现)。<behaviors> <endpointBehaviors> <behavior name="enableHttpGetRequestsBehavior"> <enableHttpGetRequests /> </behavior> </endpointBehaviors> </behaviors> <extensions> <behaviorExtensions> <!-- Enabling HTTP GET requests: Behavior Extension --> <add name="enableHttpGetRequests" type="Microsoft.ServiceModel.Samples.EnableHttpGetRequestsBehaviorElement, QueryStringFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions>
在调用 Open 之前添加操作格式化程序。
在客户端上:
客户端实现不需要更改。
客户端的 App.config 必须使用自定义 POX 绑定,将
messageVersion
元素的textMessageEncoding
属性设置为None
。 与服务的一个区别在于,客户端必须允许手动寻址,以便修改传出“收件人”地址。<bindings> <customBinding> <binding name="poxBinding"> <textMessageEncoding messageVersion="None" /> <httpTransport manualAddressing="True" /> </binding> </customBinding> </bindings>
客户端的配置项 App.config 必须指定与服务器相同的自定义参数
EnableHttpGetRequestsBehavior
。在调用 CreateChannel() 之前添加操作格式化程序。
运行示例时,操作请求和响应将显示在客户端控制台窗口中。 所有四个运算(加、减、乘和除)都必须成功。
设置、生成和运行示例
确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。
要生成解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。
若要在单台计算机或跨计算机配置中运行示例,请按照 运行 Windows Communication Foundation 示例中的说明进行操作。