近期的开发要求使用 IIS 承载的 WCF 提供数据和实现操作,客户端使用 Ajax Json 和 WinForm,因此要在统一服务上同时绑定用于 Ajax 的 webHttpBinding 和用于 WinForm 的 wsHttpBinding。
下面假定服务名为 Itoro.WebCore.Web。
在创建服务时,选择“启用了 AJAX 的 WCF 服务”,然后在 web.config 会自动在 system.serviceModel 下生成相关配置,默认的用于 Ajax 的配置是行为中的名为 Itoro.WebCore.WebAspNetAjaxBehavior 的终点行为,并且使用 <enableWebScript /> 启用 Ajax Javascript 支持。在服务配置中是一个名为 Itoro.WebCore.Web 的服务,其中的终点配置为使用 Itoro.WebCore.WebAspNetAjaxBehavior 行为并绑定到 webHttpBanding。
接下来是手动修改配置以支持 WinForm 的客户端访问,即 wsHttpBinding。
在 system.serviceModel/behaviors/serviceBehaviors 下添加如下内容(如不存在 serviceBehaviors 则在相应位置创建该元素):
< serviceMetadata httpGetEnabled ="true" />
</ behavior >
该配置指定名为 Itoro.WebCore.WebBehavior 的服务行为启用 Http 下的服务元数据。
接下来修改名为 Itoro.WebCore.Web 的服务(即 <service name="Itoro.WebCore.Web" /> 元素)为以下内容:
< endpoint address ="web" behaviorConfiguration ="Itoro.WebCore.WebAspNetAjaxBehavior"
binding ="webHttpBinding" contract ="Itoro.WebCore.Web" />
< endpoint address ="ws" binding ="wsHttpBinding" contract ="Itoro.WebCore.Web" >
< identity >
< dns value ="localhost" />
</ identity >
</ endpoint >
< endpoint address ="mex" binding ="mexHttpBinding" contract ="IMetadataExchange" />
</ service >
其中添加 service 元素中的 behaviorConfiguration,添加了2个终点配置,分别为用于 WinForm 的 wsHttpBinding 和用于元数据的 mexHttpBinding。另外,修改 webHttpBinding 和 wsHttpBinding 的 address 属性分别的 web 和 ws(也可以自定义,但是一定要设置,而且不能相同,否则会因为不同类型的绑定监听同一 Uri 而发生错误)。
完整的配置如下:
< behaviors >
< endpointBehaviors >
< behavior name ="Itoro.WebCore.WebAspNetAjaxBehavior" >
< enableWebScript />
</ behavior >
</ endpointBehaviors >
< serviceBehaviors >
< behavior name ="Itoro.WebCore.WebBehavior" >
< serviceMetadata httpGetEnabled ="true" />
</ behavior >
</ serviceBehaviors >
</ behaviors >
< serviceHostingEnvironment aspNetCompatibilityEnabled ="true" />
< services >
< service behaviorConfiguration ="Itoro.WebCore.WebBehavior" name ="Itoro.WebCore.Web" >
< endpoint address ="web" behaviorConfiguration ="Itoro.WebCore.WebAspNetAjaxBehavior"
binding ="webHttpBinding" contract ="Itoro.WebCore.Web" />
< endpoint address ="ws" binding ="wsHttpBinding" contract ="Itoro.WebCore.Web" >
< identity >
< dns value ="localhost" />
</ identity >
</ endpoint >
< endpoint address ="mex" binding ="mexHttpBinding" contract ="IMetadataExchange" />
</ service >
</ services >
</ system.serviceModel >
最后在服务使用上也要有些变动,假设我们的服务为 http://localhost/Web.svc,那么在 Ajax 网站上添加服务时应该使用 Web.svc/web,而生成的脚本引用地址为 Web.svc/web/js,其中的 web 即为 webHttpBinding 中的 address。在 WinForm 中可以直接通过 http://localhost/Web.svc 添加服务引用,在生成的 app.config 中 /configuration/system.serviceModel/client 下会有2个终点配置,其中一个是 WebHttpBinding_Web,另外一个是 WSHttpBinding_Web,因此在使用时必须指定终点为 WSHttpBinding_Web,即 WebClient client = new WebClient("WSHttpBinding_Web") 否则运行时会出现错误。
最后,因为 Web 是无状态的,而 WinForm 是有状态的,所以在 Web 下需要使用 Cookie(包括 Session),而在 WinForm 下只要 WebClient client 没有销毁就会一直保留同一状态,因为在编写服务的时候也要考虑兼容这两种模式。