WCF(Windows Communication Foundation,WCF)是基于Windows平台下开发和部署服务的软件开发包(Software Development Kit,SDK)。WCF为服务提供了运行时环境(Runtime Environment),使得开发者能够将CLR类型公开为服务,又能够以CLR类型的方式使用服务。理论上讲,创建服务并不一定需要WCF,但实际上,使用WCF却可以使得创建服务的任务事半功倍。WCF是微软对一系列产业标准定义的实现,包括服务交互、类型转换、封送(Marshaling)以及各种协议的管理。正因为如此,WCF才能够提供服务之间的互操作性。WCF还为开发者提供了大多数应用程序都需要的基础功能模块,提高了开发者的效率。WCF的第一个版本为服务开发提供了许多有用的功能,包括托管(Hosting)、服务实例管理(Service Instance Management)、异步调用、可靠性、事务管理、离线队列调用(Disconnected Queued Call)以及安全性。同时,WCF还提供了设计优雅的可扩展模型,使开发人员能够丰富它的基础功能。事实上,WCF自身的实现正是利用了这样一种可扩展模型。本书的其余章节会专注于介绍这诸多方面的内容与特征。WCF的大部分功能都包含在一个单独的程序集System.ServiceModel.dll中,命名空间为System.ServiceModel。
WCF的体系架构如下:
WCF的客户端与服务端模型如下:
1 地址
WCF的每一个服务都有唯一的地址。地址包括服务位置和传输协议(传输样式)。服务位置包括目标机器名、站点、网络、端口、管道或队列,以及一个可选的特定路径或者URI。
地址常用格式为:[基地址]/[可选的URI],如“net.tcp://localhost:8081/MyService”,可以读做“采用HTTP协议访问localhost机器,MyService服务在8081端口处等待用户的调用”
基地址常用格式为:[传输协议]://[机器名或域名][:可选端口],如“net.tcp://localhost:8081”。
WCF支持多种传输样式:
- HTTP 采用http、https协议进行传输,默认端口号80。
- TCP 采用net.tcp协议进行传输,默认地址为808。
- Peer network(对等网) 采用net.p2p进行传输,采用Windows的对等网传输机制。
- IPC(内部进程通信) 采用net.pipe进行传输,使用Windows的命名管道机制,只能接收来自同一台机器的调用,且每台机器只能打开一个命名管道。
- MSMQ 采用net.msmq进行传输,使用Windows的MSMQ机制,必须指定队列名,如果是处理私有队列,则必须指定队列类型。
2 绑定
绑定将通信模式与交互方式直接的组合进行规范,将这些通信特征合理地组合在一起。一个绑定封装了诸如传输协议、消息编码、可靠性、安全性、事务传播以及互操作性等相关选项的组合,使得它们保持一致。
WCF定义了六种常用的绑定:
- 基本绑定 由BasicHttpBinding类提供,将WCF服务公开为Web服务。
- TCP绑定 由NetTcpBinding类提供,使用TCP协议通信,支持多种特性,包括可靠性、事务性、安全性及WCF之间通信的优化,缺点是客户端必须使用WCF。
- IPC绑定 由NetNamedPipeBinding类提供,使用命名管道为同一机器的通信进行传输,支持的特性与TCP绑定类似,是性能和安全性最佳的绑定。
- Web服务绑定 由WSHttpBinding类提供,WS绑定使用HTTP或HTTPS进行传输,提供了诸如可靠性、事务性与安全性在内的多种特性,这些特性遵循WS-*标准,该绑定被设计用来与支持WS-*标准的系统进行互操作。
- WS双向绑定 由WSDualHttpBinding类提供,支持双向通信。
- MSMQ绑定 由NetMsmqBinding类提供,使用MSMQ进行传输。
3 契约
WCF的所有服务都公开为契约,契约与平台无关,是描述服务功能的标准方式。WCF包含4类契约:
- 服务契约 描述了客户端能够执行的服务操作。
- 数据契约 定义了与服务交互的数据类型。
- 错误契约 定义了服务抛出的错误,以及服务处理错误和传递错误到客户端的方式。
- 消息契约 消息契约允许服务直接与消息交互,用于定制专有的消息格式,也意味着要自己的应用程序上下文,因为会增加代码的复杂度,所以不属于常见用法。
4 终结点
终结点是WCF进行通信的唯一手段,ChannelFactory<T>本质上是通过制定的终结点创建用于进行服务调用的服务代理。终结点在WCF体系中通过Systtm.ServiceModel.Description.ServiceEndpoint类型表示,其包含三个核心属性——地址、绑定、契约。终结点是用来发送和接收消息的构造,终结点是真正意义上的接口,它包含了一个对象接口所需的全部信息。每个服务至少必须公开一个业务终结点,每个终结点有且只能拥有一个契约。服务上的所有终结点都包含了唯一的地址,而一个单独的服务则可以公开多个终结点。这些结点可以使用相同或不同的绑定,公开相同或不同的契约。
5 元数据
服务的元数据描述服务的特征,外部实体需要了解这些特征以便与该服务进行通信。服务的元数据包括XML、架构文档(用于定义服务的数据协定)和WSDL文档(用于描述服务的方法)。启用元数据后,WCF通过检查服务及其终结点自动生成服务的元数据。
6 上下文
WCF上下文将服务宿主与公开本地CLR类型为服务的上下文组合在一起,上下文是服务实例最核心的执行范围,上下文可以为空,即不包含任何服务实例。
7 宿主
WCF服务类不能凭空存在,每个WCF服务类必须托管在某个宿主进程中。单个宿主进程可以托管多个服务,而相同的服务类型也可以托管在多个宿主进程中,如果服务与客户端驻留在相同的进程中,则称为进程内托管。常用宿主如下:
- Web站点
- Windows窗体应用程序
- Windows服务
- Windows激活服务(WAS)
WCF宿主体系结构如下:
每个.NET宿主进程都包含了多个应用程序域,每个应用程序域包含零到多个宿主实例,每个服务宿主实例专门对于于一个特殊的服务类型。因此,创建一个宿主实例,实际上就是为对应于基地址的宿主机器的类型注册一个包含了所有终结点的服务宿主实例。每个服务宿主实例拥有零到多个上下文。一个上下文可以与零个或一个服务实例关联。
8 代理
WCF不允许客户端直接与服务交互,客户端使用代理将调用转发给服务。即使对象是本地的,WCF仍然使用远程编程模型的实例化方式,并且使用代理。
示例
通过上面的介绍,我们从契约,服务,宿主,客户端这四个步骤完成一个简单的Demo,项目结构如下:
定义契约,也就是一个接口,这是这个接口有ServiceContract的标记,被暴露的方法被标记为OperationContract,数据的话被标记为DataContract
namespace WCFService
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
[ServiceContract]
public interface IWCFService
{
[OperationContract]
string GetData(int value);
[OperationContract]
string Greeting(string sName);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: 在此添加您的服务操作
}
// 使用下面示例中说明的数据约定将复合类型添加到服务操作。
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
}
实现上面的接口
namespace WCFService
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
public class WCFService : IWCFService
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
public string Greeting(string sName)
{
return "Hello ," + sName;
}
}
}
通过绑定实现服务的宿主,也就是A+B+C
namespace WCFHost
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(WCFService.WCFService)))
{
host.AddServiceEndpoint(typeof(WCFService.IWCFService), new BasicHttpBinding(),
new Uri("http://localhost:10000/Service/WCFService"));
if (host.State != CommunicationState.Opening)
host.Open();
Console.WriteLine("服务已经启动!");
Console.ReadLine();
}
}
}
}
在客户端需要添加,服务契约的引用。
namespace WCFClient
{
class Program
{
static void Main(string[] args)
{
EndpointAddress ea =
new EndpointAddress("http://localhost:10000/Service/WCFService");
IWCFService proxy =
ChannelFactory<IWCFService>.CreateChannel(new BasicHttpBinding(), ea);
Console.WriteLine(proxy.Greeting("刘宇"));
Console.ReadLine();
}
}
}
执行结果
有没有看到和NETRemoting的写法有点类似呢?