一个WCF 程序通常包含三个部分,WCF Service 程序集, WCF Service Host 程序集, WCF Client 程序集。
WCF Service 程序集:实现此WCF服务主要功能的程序集合。
WCF Service Host 程序集:一个可执行文件或是一个服务,能够运行在系统中,作为WCF Service的载体。
WCF Client 程序集:通过Proxy可以和WCF Service通信,并获取服务的应用程序。
创建一个WCF应用程序一共需要5个步骤:
Defining Service Contract
Implementing Service Contract
Configuring Service EndPoints (Option)
Hosting Service in an Application
Building a Client Application
使用 Visual Studio 2010 创建 WCF
创建工程,其中可以使用WCF Service Library 和 WCF Service Application 来创建自己WCF 应用程序。
WCF Service Library:不包含WCF Host Application,仅是一个WCF Service简单的库,可以被包含到其他任意的Host中。
WCF Service Application:工程中包含了WCF Hosting Application,创建后可以直接使用。
可以有2种方法来实现WCF Service,仅 使用代码 和 代码+配置文件。这两种方式其实主要指的是描述WCF Service对外接口的信息。
例如定义WCF Service Endpoints 的地址,绑定信息,服务合约等,我们可以用代码来直接定义,也可以把这些信息放到配置文件中,这样当信息改变时无需重新编译代码。
方式 一:直接使用代码
创建WCF Service 程序时一定要使用 namespace: using System.ServiceModel;
关键字 [ServiceContract]:描述服务的类型
关键字 [OperationContract]:描述服务的接口
关键字 [DataContract]:描述服务的数据
应用实例:
Step 1:定义并实现Service 的接口(对应上述 5个步骤中的 1 和 2)
其中定义了一个WCF Service 的一个接口 AddTax 并且 类 AddTaxService 继承并实现了这个接口。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace AddTaxServiceLib
{
[ServiceContract]
public interface IAddTax
{
[OperationContract]
decimal AddTax(decimal productCost, double taxRate);
}
public class AddTaxService : IAddTax
{
public decimal AddTax(decimal productCost, double taxRate)
{
return productCost + (productCost * (decimal)taxRate);
}
}
}
Step 2:创建一个WCF Service Host(对应上述 5个步骤中的 3 和 4)
这里的WCF Service Host Application 就是一个简单的控制台应用程序。这里又创建了一个WCF Service Host 的工程。
创建好工程后别忘记在Reference中加入System.ServiceModel 和 WCF Service 的Lib。
在Host 程序中分别定义 address,binding 和 contract。
address: 是client 用来和 host通信的地址
Uri address = new Uri("http://localhost:8080/AddTaxService");
myServiceHost = new ServiceHost(typeof(AddTaxService), address);
binding: 用来描述Endpoint的通信的channel,它至少包括了网络适配层的channel,但也可以配置一些其他的 channel,例如加密等。
WCF 库中提供了一些预定义的channel (BasicHttpBinding,WsHttpBinding,NetTcpBinding),基本上从名字也可以猜出其含义了,基于不同的网络协议。
BasicHttpBinding binding = new BasicHttpBinding();
contract: 描述WCF Service服务接口信息。
Type contract = typeof(IAddTax)
定义好了 address, binding 和contract 后我们就可以添加Endpoint了。
myServiceHost.AddServiceEndpoint(contract, binding, address);
我们虽然定义好了一个Endpoint, 但这时候Client端还没有任何Service端的信息,也就无法和Service端进行通信。
这时候就需要Service端提供一组元数据(Metadata)来描述Service的信息,并且提供给Client端。
这个过程则是通过 MEX endpoint 来实现的,它也是一个endpoint,与客户自定义的endpoint的不同在于它的功能就是向Client提供Service 的信息帮助Client与Service实现通信。
步骤 1:当Client 想与Service端进行通信时,它首先会与Service端的MEX Endpoint 进行通信
步骤 2:Service端的MEX Endpoint 会通过 Web Service Definition Language (WSDL) 把Service端的信息发送到Client 端
步骤 3:Client根据Service端的信息创建 Proxy 和 Configuration File,来与 Service端进行通信。
在Service代码中添加 MEX Endpoint 首先 添加一个behavior
别忘了使用 namespace : using System.ServiceModel.Description;
// Adding Service Metadata behavior
ServiceMetadataBehavior mexbehavior = new ServiceMetadataBehavior();
mexbehavior.HttpGetEnabled = true;
myServiceHost.Description.Behaviors.Add(mexbehavior);
然后添加 MEX Endpoint 的 address binding 和 contract
例子中添加了一地址为 http://localhost:8080/AddTaxService/mex 的MEX Endpoint, 通过Http 协议进行通信
//Adding Metadata behavior
ServiceMetadataBehavior mexbehavior = new ServiceMetadataBehavior();
mexbehavior.HttpGetEnabled = true;
myServiceHost.Description.Behaviors.Add(mexbehavior);
myServiceHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
实例代码下载:使用代码实现的 WCF Service Application。
方式 二:使用代码 + 配置文件
根据上述说明的实现WCF Application的5个步骤,首先还是要定义并实现WCF Service。
这步与方式一中的实现方法是一致的,不在赘述。
其次是实现一个 WCF Host Application,这里与上个例子中有所不同,基本不需要配置任何的Endpoint 信息和MEX Endpoint信息。这些信息将全部放入在配置文件中。
Host 的实例代码:可以看到其中没有配置任何关于Endpoint和 address, binding,还有 contract的信息。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using AddTaxServiceLib;
namespace TestServiceHost
{
static class AddTaxServiceHost
{
private static ServiceHost myServiceHost;
static void Main(string[] args)
{
myServiceHost = new ServiceHost(typeof(AddTaxService));
myServiceHost.Open();
Console.WriteLine("Press <enter> to termintered WCF service");
Console.ReadLine();
myServiceHost.Close();
}
}
}
配置文件写法:
配置文件包括一个<system.serviceModel> Node, 在它下面又包含了<services>,<bindings> , <behaviors>, <hosts>,<endpoints>,<clients>等节点。
下面是一个该例子中XML配置文件的例子 FileName: App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="AddTaxServiceLib.AddTaxService"
behaviorConfiguration="AddTaxServiceBehavior">
<host>
<baseAddresses> <add baseAddress = "http://localhost:8080/AddTaxService" /> </baseAddresses>
</host>
<!-- Service Endpoints -->
<endpoint address ="" binding="basicHttpBinding" contract="AddTaxServiceLib.IAddTax"> </endpoint>
<!-- Metadata Endpoints -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="AddTaxServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
与代码实现的WCF例子相比较,可以很容易理解该配置文件中的内容。
关于默认的Endpoint
在WCF 4中,它不会抛出任何异常,即使WCF Service没有配置任何的Endpoint,系统也会使用默认的EndPoint来进行处理。当然结果肯定不会是Client所希望的。
WCF 4 中定义了一个 public 方法 AddDefaultEndPoints,用户可以直接使用来添加默认的EndPoint。该方法为每个base address添加一个默认的EndPoint。
假设WCF Service定义了三个 Service Contract,但只配置了一个Base Address,在这种情况下,AddDefaultEndPoint会添加三个默认的 EndPoint。
再例如,假设WCF Service定义了二个 Service Contract,配置了两个Base Address,在这种情况下,AddDefaultEndPoint会添加四个默认的 EndPoint。
例如代码:Service 中有2个接口:IWelcome 和 IAddTax。
情形 1: 其中并没有添加 Endpoint 的代码。
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WelcomeToAddTasService),
new Uri("http://localhost:8080/WelcomeToAddTasServcie"),
new Uri("net.tcp://localhost:8081/WelcomeToAddTasServcie"));
host.Open();
foreach(SercideEndPoint se in host.Descritpion.Endpoints)
Console.WriteLine("A: {0}, B: {1}, C: {2}", se.Address, se.Binding.Name, se.Contract.Name);
Console.WriteLine("Press <Enter> to stop the service");
Console.ReadLine();
host.Close();
}
}
可以看到,系统默认添加了4个EndPoint
情形 2: 主动添加了 EndPoint。
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WelcomeToAddTasService),
new Uri("http://localhost:8080/WelcomeToAddTasServcie"),
new Uri("net.tcp://localhost:8081/WelcomeToAddTasServcie"));
host.AddServiceEndpoint(typeof(IWelcome), new WSHttpBinding(), "myendpoint");
host.Open();
foreach(SercideEndPoint se in host.Descritpion.Endpoints)
Console.WriteLine("A: {0}, B: {1}, C: {2}", se.Address, se.Binding.Name, se.Contract.Name);
Console.WriteLine("Press <Enter> to stop the service");
Console.ReadLine();
host.Close();
}
}
此时系统不会添加任何的默认的EndPoint.
情形 3: 主动添加了 EndPoint,并且掉用了 AddDefaultEndpoints 函数
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WelcomeToAddTasService),
new Uri("http://localhost:8080/WelcomeToAddTasServcie"),
new Uri("net.tcp://localhost:8081/WelcomeToAddTasServcie"));
host.AddServiceEndpoint(typeof(IWelcome), new WSHttpBinding(), "myendpoint")
host.AddDefaultEndpoints();
host.Open();
foreach(SercideEndPoint se in host.Descritpion.Endpoints)
Console.WriteLine("A: {0}, B: {1}, C: {2}", se.Address, se.Binding.Name, se.Contract.Name);
Console.WriteLine("Press <Enter> to stop the service");
Console.ReadLine();
host.Close();
}
}
WCF4 中当然定义了一套默认的 Endpoint和传输协议对应关系的配置信息。当调用 AddDefaultEndponts方法时,系统可以通过这些配置信息找到 binding的方式。
文件:machine.config.comments 中定义如下:
<System.ServiceModel>
<ProtocolMapping>
<add scheme="http" binding="basicHttpBinding" bindingConfiguration=""/>
<add scheme="net.tcp" binding="netTcppBinding" bindingConfiguration=""/>
<add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration=""/>
<add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration=""/>
</ProtocolMapping>
关于标准的 Endpoint
WCF 同时还定义了一些标准的 Endpoint。(MEXEndpoint, DynamicEndpoint, discoveryEndpoint)
使用Standard Endpoint只需要指定他们的名字就可以了。
例如:
<configuration>
<system.serviceModel>
<services>
<endpoint kind="basicHttpBinding" contract="IWelcome"/>
<endpoint kind="mexEndpoint" address="mex"/>
</services>
</system.serviceModel>
</configuration>
实例代码下载:使用配置文件实现的WCF Service Application。
下一篇将继续介绍 WCF 的 Client 端。