WCF方面的HelloWorld例子网上已经很多了。再写这个显得有些“Out”了,不过只是作为笔记写一下。本篇使用的场景是从网上看到的:WCF服务端创建一个服务并公开地址。WCF客户端访问该地址并发送字符串数据。服务端收到数据之后组合一个新的字符串数据并返回给客户端显示。
下图是运行时的效果,源码在此下载。

项目结构及开发步骤

本示例中所有的项目都是采用类库的方式创建的,在开发过程中需要手工去添加System.ServiceModel组件和命名空间。Visual Studio 2005/2008有专门创建WCF的模板,如果为了省事的话也可以直接使用该模板。以下是简单的在开发步骤及说明。
第一步 创建服务协定(Interface)
Cbcye.Contract 用于创建服务的协定(契约),该协定中描述了服务提供的方法集,本示例只创建了一个GetString的方法。该协定需要在服务端和客户端都实现。
最开始学的时候对这个服务端和客户端都需要实现服务协定不是很理解,以为如果通过DLL引用的方式来实现服务协定共享的话那么是不是会限制WCF的应用范围,现在了解到其实服务的协定是可以通过WSDL来描述的,那就是说像Web Service一样,其他非WCF的应用程序也可以使用。
第二步 根据服务协定实现服务(具体是做什么的)
Cbcye.Service 用于创建服务,就是根据服务协定实现服务的具体方法,比如本示例中的使用
第三步 创建承载服务的应用程序(服务在哪运行)
Cbcye.ServiceConsoleHost 用于承载服务,就是该服务是由哪个应用程序来运行的。本示例中采用Windows控制台应用程序来承载服务
[3] 将服务托管在控制台应用程序
服务的配置信息存放到App.Config里

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<!-- WCF 配置声明-->

<system.serviceModel>

<services>

<!-- 服务名称跟Cbcye.Service项目中的一致,使用命名空间.类名 -->

<service name="Cbcye.Service.HelloWorldService">

<!--

address - 指定这个Endpoint对外的URI,这个URI可以是个绝对地址,也可以是个相对于baseAddress的

相对地址。如果此属性为空,则这个Endpoint的地址就是baseAddress

binding - 指定这个Endpoint使用的binding,这个banding可以是系统预定义的9个binding之一,

比如是basicHttpBinding,也可以是自定义的customBinding。binding决定了通讯的类型、

安全、如何编码、是否基于session、是否基于事务等等。

contract- 指定这个Endpoint对应的Contract的全限定名(名称空间.类型名),这个Contract应该是被

service元素的name指定的那个service实现。

name - Endpoint的名称,可选属性,每个Contract都可以有多个Endpoint,但是每个Contract对应的

多个Endpoint名必须是唯一的

-->

<endpoint address="" binding="basicHttpBinding" contract="Cbcye.Contract.IHelloWorld" name=""></endpoint>

<host>

<baseAddresses>

<!-- 在此可以定义每种传输协议的baseAddress,用于跟使用同样传输协议Endpoint定义的相对地

址组成完整的地址,但是每种传输协议只能定义一个baseAddress。HTTP的baseAddress同时是service

对外发布元数据的URL-->

<add baseAddress="http://localhost:7788/cbcye/helloworld%22/>

</baseAddresses>

</host>

</service>

</services>

</system.serviceModel>

</configuration>

第四步 创建客户端调用服务
Cbcye.Client 用于消费WCF服务端提供出来的服务,由于客户端也需要实现服务协定(第一步创建的)因此需要在服务端创建代理类用于实现协定。
客户端代理类代码
客户端调用程序代码
客户端应用程序配置

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<system.serviceModel>

<client>

<!--参照Host项目的配置文件注释-->

<endpoint address="http://localhost:7788/cbcye/helloworld%22 binding="basicHttpBinding" contract="Cbcye.Contract.IHelloWorld"></endpoint>

</client>

</system.serviceModel>

</configuration>
总结
Ok,第一个WCF应用程序已经实现完了,本程序为了简便开发过程,将WCF的配置信息都放到了App.Config来配置。也体现了WCF框架的高效和灵活性。WCF基本概念请参见《WCF服务编程-基础》