WCF服务配置是WCF服务编程的主要部分。WCF作为分布式开发的基础框架,在定义服务以及定义消费服务的客户端时,都使用了配置文件的方法。虽然WCF也提供硬编程的方式,通过在代码中直接设置相关对象的属性来完成服务端与客户端的配置,然而这种方式并不利于后期程序的更改和扩展。因此,配置文件给WCF程序编程带来了极大的便利性,通过配置文件配置服务,可提供在部署时而非设计时提供终节点和服务行为数据的灵活性。正因如此,WCF的框架有着极大的伸缩性和自定义性。
WCF配置文件的结构如下图所示,包含3个部分,services(服务)、bindings(绑定)、behaviors(行为)
1.services节点
每个服务的发布都会包含有一个service节点,里面包含一个或者多个endpoint(终结点)。Service元素具有如下属性:
endpoint指定用于公开服务的服务终结点的绑定、协定和地址属性。与WCF的所有通信是通过该服务的终结点进行的,利用终结点,WCF服务可以访问WCF提供的功能。常用属性如下:
元数据终结点:WCF服务通过发布一个的或者多个元数据终结点来发布元数据。发布元数据后可以通过标准协议(如WS-MetadataExchange(MEX)和Http/Get请求)来使用该元数据。元数据终结点类似于其他服务终结点,他们 都需要第一个地址、一个协定、一个绑定。若要启用发布元数据终结点,必须将ServiceMetadataBehavior服务行为添加到该服务。默认情况下,WCF服务不发布元数据终结点,所以必须将他们显示的添加到服务配置中才能为 服务启用元数据发布。如下图所示:
Note: WCF元数据相关概念
WCF服务元数据是什么?
WCF服务元数据是WCF服务的核心部分服务地址(Address)、绑定(通信协议Binding)、契约(服务、操作、数据Contract)的原始描述信息。服务所公开的元数据包括 XSD(文档中出现的元素、文档中出现的属性、子元素、子元素的数量、子元素的顺序、元素是否为空、元素和属性的数据类型、元素或属性的默认和固定值)和 WSDL 文档(用于描述服务的方法、参数、参数个数、顺序、返回值、返回值的类型等方法的相关信息)。.Disco文档(描述服务的协议、地址、命名空间等信息)。
这些关键的WCF服务元数据全部都是基于XML语言描述,支持核心的行业标准协议。XSD好处显而易见, 基于XML,没有专门的语法 ,XML Schema支持一系列的数据类型(int、float、Boolean、date等) ,可扩充的数据模型,支持综合命名空间 ,支持属性组等。而这些正式WCF分布式服务追求的跨语言、跨平台的关键部分所在。
为什么要暴露服务元数据?
知道了WCF服务元数据的概念后,我们就能理解为什么要暴露服务的元数据。WCF服务的元数据描述服务的核心信息,客户端需要了解这些特征以便与该服务进行通信。要想实现异构平台或者系统之间的通信,以前的技术是使用Web Service.因为其具有自描述、可扩展、与平台无关等优势。客户端只需要根据Web Service地址,便可获取服务的相关信息,反序列话本地的代码,通过服务代理进行服务的调用。
WCF服务主要特性之一就是跨平台的服务交互。而暴露服务元数据的重要原因就是解决了异构客户端服务交互的关键问题。 元数据基于XML,自描述。客户端可以根据服务的元数据反序列换生成本地代码,无论是c#,vb还是java语。
2.bindings节点
配置绑定所需要的节点属性,绑定用于连接WCF服务终结点所需要的详细信息,所以每个终结点必须正确配置绑定信息,绑定最起码需要指定使用的传输机制(HTTP/TCP),还可以设置其他特征,如安全和事务支持。绑定信息可能很复杂,也可能很简单,一般来说绑定包含的如何连接到终结点的信息属于以下类别中的一种。
3.behaviors节点
包含serviceBehaviors(服务行为)、endpointBehaviors(终结点行为)的配置。
Note:具体参照MSDN
https://msdn.microsoft.com/zh-cn/library/aa967282(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/vstudio/ms731403(v=vs.100).aspx
接下来,我们照常写个实例,实例很简单,工程结构如右图所示:
using System.ServiceModel; namespace Service { [ServiceContract] public interface IReqReply { [OperationContract] string SayHello(string name); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Service { public class ReqReply:IReqReply { public string SayHello(string name) { return "Hello "+name; } } }
Host工程的App.config配置文件如下:
<?xml version="1.0"?> <configuration> <system.serviceModel> <services> <service name="Service.ReqReply" behaviorConfiguration="ReqReplyBehavior"> <host> <baseAddresses> <add baseAddress="http://127.0.0.1:1234/ReqReply/"/> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding" contract="Service.IReqReply" bindingConfiguration="binding1" behaviorConfiguration="behavior1"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <bindings> <wsHttpBinding> <binding name="binding1"> <security mode="Message"> <message clientCredentialType="Windows"/> </security> </binding> </wsHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="ReqReplyBehavior"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="True"/> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="behavior1"> <dataContractSerializer maxItemsInObjectGraph="2147483647"/> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
寄宿服务,Program.cs的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using Service; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost ReqReplyHost = new ServiceHost(typeof(ReqReply))) { ReqReplyHost.Opened += delegate { Console.WriteLine("请求响应通讯服务已经启动,按任意键终止!"); }; ReqReplyHost.Open(); Console.Read(); } } } }
引用服务http://127.0.0.1:1234/ReqReply/,将服务命名为:ReqReplyServiceRef,客户端调用代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Client.ReqReplyServiceRef; namespace Client { class Program { static void Main(string[] args) { ReqReplyClient proxy = new ReqReplyClient(); Console.WriteLine(proxy.SayHello("WCF")); Console.Read(); } } }