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方法中,格式化器从接收的请求消息属性中检索ViaURI。 它将 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 示例中的说明进行操作。