Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台。整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术。它跟WebService一样,也是Windows平台上开发分布式应用的一种方式。
WCF编程之前,一定要搞明白几个概念:契约;寄宿;宿主。
1.契约: 契约是一种双边或多边的协议,是利益相关方就某个问题达成的一种共识,契约确保了服务的正常调用,客户端以契约的方式进行服务调用,而服务则需要照契约规定的方式提供服务。契约是服务提供的一组操作的描述,从功能上讲每个操作对应着某个具体的功能实现,以及调用这个操作的输入和输出;从消息交换层面上讲,每个操作定义了所采用的消息交换模式和消息本身的结构。特别提一下,契约有4种,服务契约,数据契约,异常契约,消息契约,入门先讲最简单的服务契约。
2.寄宿: 服务添加到宿主的过程。
3.宿主: 就是托管平台,寄宿于一个运行着的进程中,我们把这种平台或者进程称之为宿主,一般有4种,控制台、Windows窗体程序、IIS及Windows服务。
下面着重讲述创建到发布的过程,先实现最简单的服务契约控制台自我寄宿入手。新建控制台项目wcf-service,实现对wcf服务的寄宿,该项目引用System.ServiceMode程序集(WCF框架的绝大部分实现和API定义在该程序集中)。新建控制台wcf-service:实现对服务的调用端,该项目引用System.ServiceMode程序集(生成的代理类继承自该程序集)。新建一个契约操作方法:建一个接口,贴上标签,至于标签什么用途及含义,等接下几篇深扒在探讨。添加一个接口实现类,来实现方法,见下代码:
[ServiceContract]
public interface ICar
{
[OperationContract]
string Run(int distance);
}
public class CarService : ICar
{
public string Run(int distance)
{
return "行驶了" + distance.ToString();
}
}
开始寄宿,WCF采用终结点的通信方式,终结点包括Address,Binding,Contract,简称ABC。
Address: 指定wcf的location
Binding: 指定传输协议。(tcp http msmq等)
Contract: 指定服务的Behavior。
class Program
{
static void Main(string[] args)
{
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(CarService)))
{
//指定服务的终结点,分别指定Contract,Binding,Address
host.AddServiceEndpoint(typeof(ICar), new BasicHttpBinding(), "http://localhost:10000/Car");
host.Open();
Console.WriteLine("服务启动成功");
Console.Read();
}
}
}
}
用管理员身份启动wcf-service.exe,服务以及寄宿成功,但调用呢?实际上,这样的方式是无法被调用的。客户端引用的地址是服务的元数据。所以我们需要把服务的元数据暴露出来。
class Program
{
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(CarService)))
{
if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
{
//服务的元数据 允许Get方式从下面的Url中获取
var behavior = new ServiceMetadataBehavior
{
HttpGetEnabled = true,
HttpGetUrl = new Uri("http://127.0.0.1:3721/Car/Metadata")
};
host.Description.Behaviors.Add(behavior);
}
//指定服务的终结点,分别指定Contract,Binding,Address
host.AddServiceEndpoint(typeof(ICar), new BasicHttpBinding(), "http://127.0.0.1:3721/Car");
host.Opened += (o, e) => Console.WriteLine("服务启动成功");
host.Open();
Console.Read();
}
}
}
服务的调用有2种方式,VS引用服务生成代理对象,Code自定义代理对象(需要保证Endpoint完全一致)。先说自定义代理对象:
class Program
{
static void Main(string[] args)
{
//一致的终结点
using (var channelFactory = new ChannelFactory<ICar>(new BasicHttpBinding(), "http://127.0.0.1:3721/Car"))
{
//手动创建代理对象
var proxy = channelFactory.CreateChannel();
Console.WriteLine(proxy.Run(3));
}
Console.Read();
}
}
注意,确保服务寄宿程序运行,否则客户端无法调用方法。
引用生成代理对象,先确保服务寄宿程序运行,添加Web引用,地址"http://127.0.0.1:3721/Car/Metadata",可以看到自动生成一个wcf_client.ServiceReference.CarClient代理类,然后我们新建一个代理对象,完成函数调用:
static void Main(string[] args)
{
//new 代理对象
wcf_client.ServiceReference.CarClient carclent = new
wcf_client.ServiceReference.CarClient();
Console.WriteLine(carclent.Run(3));
}
创建服务除了可以用代码,也可以通过App.config来配置。
<system.serviceModel>
<services>
<service name="wcf.consoleconfig.CarService">
<host>
<!--<可通过基址生成代理类>-->
<baseAddresses>
<add baseAddress="http://127.0.0.1:6000"/>
</baseAddresses>
</host>
<endpoint address="car" binding="wsHttpBinding" contract="wcf.consoleconfig.ICar"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpGetUrl="http://127.0.0.1:5000/tttt"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
如果不设定基址,address一定要写绝对地址;若设定,只需要写相对地址,本例address实质为"http://127.0.0.1:6000/car"。
在WCF中有两种地址,一种是访问endpoint时候用到地址;另外一种是服务描述的地址,在wcf中被称为iserviceMetadata,通过它能够产生代理类,比如本例设置: "http://127.0.0.1:5000/tttt"。前者是不用代理类生成代理对象,直接访问终结点地址;后者则是生成代理对象使用,只代表在"http://127.0.0.1:5000/Service/?wsdl"上能找到服务描述,所以它跟endpoint地址端口都不一样。
后台引用,可以自定义访问和代理类生成代理对象:
static void Main(string[] args)
{
//代理类生成代理对象
//ServiceReference1.CarClient carclient = new ServiceReference1.CarClient();
//Console.WriteLine(carclient.Run(3));
//Console.Read();
//终结点地址
using (var channelFactory = new ChannelFactory<ICar>(new WSHttpBinding(), "http://127.0.0.1:6000/car"))
{
//手动创建代理类
var proxy = channelFactory.CreateChannel();
Console.WriteLine(proxy.Run(3));
}
Console.Read();
}
总结
WCF控制台自我寄宿,服务端只可通过配置文件来实现服务的创建、寄宿和暴露元数据,也可通过代码;客户端可以采用引用服务方式来生成代理对象,也可代码写代理对象。
对WCF基本实现有初步认识,但基本的IIS发布及配置来完成寄宿还未写,请看下一篇。