一、 配制文件的简述
4.1 地址 (Addresses)
每个服务都会关联到一个唯一的地址。地址提供了两个重要信息: 服务位置(location)、传送协议(transport protocol)。WCF 1.0 支持 HTTP、TCP、Peer network、IPC (Inter-Process Communication over named pipes) 和 MSMQ。
下面是一些常用地址的例子。
http://localhost:8001
http://localhost:8001/MyService
net.tcp://localhost:8002/MyService
net.pipe://localhost/MyPipe
net.msmq://localhost/private/MyService
net.msmq://localhost/MyService
4.2 端点 (Endpoints)
端点本身就是地址、契约和绑定的组合体。
单个服务提供多个端点
<service name = "MyService">
<endpoint address = "http://localhost:8000/MyService/"
binding = "wsHttpBinding" contract = "IMyContract" />
<endpoint address = "net.tcp://localhost:8001/MyService/"
binding = "netTcpBinding" contract = "IMyContract" />
<endpoint address = "net.tcp://localhost:8002/MyService/"
binding = "netTcpBinding" contract = "IMyOtherContract" />
</service>
单个服务多个地址
一个或多个默认的基本地址(Base Address),这样在端点设置中只需提供相对地址。多个基本地址之间不能冲突,不能在同一个端口进行监听。
<service name = "MyService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/" />
<add baseAddress="net.tcp://localhost:8081/" />
</baseAddresses>
</host>
<endpoint
address = "MyService" <!-- http://localhost:8080/MyService -->
binding = "wsHttpBinding" contract = "IMyContract" />
<endpoint
address = "MyService" <!-- net.tcp://localhost:8081/MyService -->
binding = "netTcpBinding" contract = "IMyContract" />
<endpoint
address = "net.tcp://localhost:8002/MyService/"
binding = "netTcpBinding" contract = "IMyOtherContract" />
</service>
代码中对端点参数进行设置
ServiceHost host = new ServiceHost ( typeof ( Service1 ) );
host.AddServiceEndpoint ( typeof ( IService1 ) , new WSHttpBinding ( ) , "http://localhost:8000/MyService" );
host.AddServiceEndpoint ( typeof ( IService1 ) , new NetTcpBinding ( ) , "net.tcp://localhost:8001/MyService" );
host.AddServiceEndpoint ( typeof ( IService1 ) , new NetTcpBinding ( ) , "net.tcp://localhost:8002/MyService" );
host.Open ( );
4.3 绑定 (Bindings)
多数时候,我们都是直接使用 WCF 提供的 Bindings,只需对其属性作些简单的调整。当然,我们也可以从零开始写一个自定义的 Bindings 用于某些特殊的场合。服务通过元数据发布它所选择的 Bindings, 以允许客户端查询其类型和特定的属性,客户端必须严格使用相同的 Bingings 设置才能调用该服务。每个服务都可绑定多个基于不同地址 Bindings。
标准绑定类型
WCF 提供了 9 种标准的绑定类型。
· Basic binding : BasicHttpBinding。被设计用来对遗留下来的 ASMX Web Service 提供支持,这样既有的客户端程序可以连接到 WCF 服务上,而且 WCF 客户端也可以使用现有的 Web Service 服务。最简单的绑定类型,通常用于 Web Services。使用 HTTP 协议,Text/XML 编码方式。
· TCP binding : NetTcpBinding。使用 TCP 在 Intranet 网络进行跨机器通讯,支持多种功能,包括可靠性、事务和安全,并专门针对 WCF-to-WCF 进行了优化。不过相应地,它需要客户端和服务都使用 WCF 环境。效率最高,安全的跨机器通讯方式。
· Peer network binding : NetPeerTcpBinding。使用 P2P 网络进行通讯,这恐怕是使用率最少的一种绑定类型了。
· IPC binding : NetNamedPipeBinding。在同一主机上使用命名通道进行通讯,它拥有极高的安全保护能力,不接受任何本机以外的调用,和 TCP Binding 一样支持多种功能。
· Web Service (WS) binding : WSHttpBinding。使用 HTTP/HTTPS 在 Internet 上进行消息传输,支持可靠性、事务、安全等功能。比 BasicHttpBinding 更加安全,通常用于 non-duplex 服务通讯
· Federated WS binding : WSFederationHttpBinding。专用的 WS-Federation 绑定协议。
· Duplex WS binding : WSDualHttpBinding。和 WS binding 类似,但它支持服务和客户端之间的双向通讯。和 WSHttpBinding 相比,它支持 duplex 类型的服务。
· MSMQ binding : NetMsmqBinding。对离线消息队列调用提供支持。两个端点程序必须都是 .NET 的系统。
· MSMQ integration binding : MsmqIntegrationBinding。在 WCF 消息和 MSMQ 消息之间进行转换,被设计用来对遗留下来的 MSMQ 客户端提供支持。
4.4 宿主 (Hosting)
每个宿主进程可以寄宿多个服务,每种服务也可以在宿主进程中寄宿多次(地址不能相同)。
4.4.1 IIS Hosting
使用 IIS (Microsoft Internet Information Server) 作为服务宿主最主要的优势是:宿主进程会在客户端第一次发出请求时自动启用,还可以直接使用 IIS 的生命周期管理策略。而最主要的劣势则是:我们无法使用 HTTP 以外的传输模式。在 IIS5 环境下,让所有服务使用相同的端口号也会非常麻烦。
使用 IIS 作宿主非常像 ASMX web service,你必须创建一个虚拟目录(virtual directory),并且还要进行一些必要的配置使其支持 .svc 文件。.svc 文件如同 .asmx,用于识别服务代码文件和类型。(需要配置码?我安装 .NET FX 3.x 后就已经配置好了啊)
创建一个“WCF服务应用程序”
4.4.2 Self-Hosting
采用 Self-hosting,开发人员必须自己来管理宿主进程的生命周期。这种宿主通常是 Windows Forms Application、Console Application 、Windows NT Service 。我们必须显式使用 ServiceHost 实例来注册服务,并在客户端调用前调用 Open() 方法启动这些宿主。
using ( ServiceHost selfHost = new ServiceHost ( typeof ( Calculator ) ) )
{ selfHost.Open ( ); }
4.4.3 WAS Hosting
Windows Activation Service (WAS) 作为 IIS7 的一部分,只有 Windows Vista 和 Windows Server 2008 默认提供支持。WAS 比 self-hosting 拥有更多的优势,包括应用程序池(application pooling)、循环回收(recycling)、空闲管理(idle time management)、身份管理(identity management)、隔离(isolation) 等等。
一、 服务的简述
A. 在实际开发中,我们往往会将 "ABC" 反过来进行。首先定义及实现契约,然后选择合适的绑定模式,最后定义服务的地址。
B. OperationContract 只能用于 Method,只有添加了此特性的方法才能被客户端调用。它甚至可以用来标注私有方法,这显然超出了面向对象的规则,而更多的是 SOA 的方式。
C. DataContractAttribute、DataMemberAttribute 来标注自定义数据类型,这样我们就可以在服务方法中传递复杂的数据体了。使用之前,我们需要添加 System.Runtime.Serialization.dll 引用。ServiceContract、OperationContract 执行运算,而使用 DataContract、DataMember 作为可序列化的数据载体。当然,我们也可以使用 "[Serializable]" 代替 "[DataContract]"。
D.
ServiceContract
ConfigurationName: 其设置信息在配置文件中的名称。
Name / Namespace:自定义该服务契约的名称和命名空间。建议设置服务契约的 Name 和 Namespace,这样生成的客户端的代理文件会使用自定义名称来命名相关代理类型,即便我们日后对服务器端的契约名称进行重构也不会影响到客户端。
SessionMode:设置服务契约的 Session 方式,包括 Allowe、NotAllowed、Required。SessionMode 需要相应的 Binding 支持,默认情况下会自动启用,另外我们还会和 ServiceBehaviorAttribute.InstanceContextMode 配合使用来管理服务对象的生命周期。
CallbackContract:设置 duplex 模式时的回调类型。
ProtectionLevel:指定消息保护方式,可以对消息进行加密和签名处理。
OperationContract
AsyncPattern:用于定义异步服务方法。
IsInitiating:指示服务方法能否启动一个 Session。
IsTerminating:指示服务方法调用完成是否结束 Session。
DataContract
Name / Namespace:自定义名称和命名空间。
DataMember
Name:自定义名称。
IsRequired:指示该成员序列化前必须被赋值。
一、 客户端编程
6.1常用方法
我们可以使用 Visual Studio 2008 导入服务元数据来生成代理。如果服务是自宿主(self-hosted),那么需要我们在导入操作前启动服务进程。在解决方案管理器(Solution Explorer)中项目服务引用(Project Service References)添加引用即可。如果服务宿主在 IIS 或 WAS 中,我们无需事先启动服务,它们会在接收到请求时自动为我们准备好服务环境。
ClientBase<T> 接受一个标示服务契约类型的泛型参数。Channel 属性就是该参数类型。要使用代理,客户端首先需要创建代理实例,我们可以在构造方法中指定具体的端点配置名称或者创建一个端点实例。客户端在调用完代理方法后,必须关闭代理实例。
MyContractClient proxy = new MyContractClient("MyEndpoint");
proxy.MyMethod( );
proxy.Close( );
如果配置文件中该服务契约只有一个端点设置,可以省略构造参数。
MyContractClient proxy = new MyContractClient( );
proxy.MyMethod( );
proxy.Close( );
6.1使用通道
我们可以用通道(channel)代替静态代理(svcutil proxy),直接调用服务操作。ChannelFactory<T> 允许我们在运行时动态创建一个代理与服务进行交互。我们需要从配置文件中获取一个端点配置名称,将其提交给 ChannelFactory<T> 构造方法,也可以直接使用相应的绑定和地址对象作为参数。然后,调用 CreateChannel() 方法获取动态生成代理对象的引用。有两种方法关闭代理,将通道转型成 IDisposable,并调用 Dispose() 方法关闭代理;或者转型成 ICommunicationObject,调用 Close() 方法。
ChannelFactory<IService1> factory = new ChannelFactory<IService1> ( );
IService1 proxy1 = factory.CreateChannel ( );
using ( proxy1 as IDisposable ) { proxy1.GetData ( 0); }
IService1 proxy2 = factory.CreateChannel ( );
proxy2.GetData ( 0 );
ICommunicationObject channel = proxy2 as ICommunicationObject;
Debug.Assert ( channel != null ); // Debug =using System.Diagnostics;
channel.Close ( );
注:使用通道编程时,我们需要直接引用和服务器相同契约的程序集(dll)。当然,也可以使用 SvcUtil 生成的契约接口代码。
评论