实例一: 构建一个简单的WCF Service: MagicEightBall (问问题,自动回答)。
首先回顾一下WCF程序集之间的关系,理解WCF Host和Client之间的通信架构
实现WCF通信的思路就是:
创建WCF Service(包括定义Contract和Service,配置Config文件) -> 承载(寄宿)宿主(Host) -> 客户端程序创建Proxy,实现和WCF Service进行通信。
具体步骤如下:
1. 创建Contracts类库,创建WCF Service的接口 IEightBall 。
1)添加引用(.NET)System.ServiceModel.dll程序集,并引用System.ServiceModel命名空间。
2)将WCF Service接口标记 [ServiceContract]特性,每个接口成员标记[OperaionContract]特性。
- <span style="">using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ServiceModel;
- namespace Contracts
- {
- //为了使接口称为WCF Services接口,必须用[ServiceContract]特性加以标记
- [ServiceContract]
- public interface IEightBall
- {
- //Ask one question ,and then get an answer.
- //WCF框架中使用的方法必须用[OperationContract]特性来修饰。
- [OperationContract]
- string ObtainAnswerToQuestion(string userQuestion);
- }
- }</span>
2. 创建Services类库,对Service接口IEightBall进行实现。
1)添加引用Contracts Project,并在代码中引用Contracts命名空间。
2)定义对接口实现的具体的内容。
- <span style="">using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Contracts;
- namespace Services
- {
- public class EightBallService : IEightBall
- {
- //Constractor , just display message in Host.
- public EightBallService()
- {
- Console.WriteLine("The 8-ball awaits your question... ");
- }
- //Services method for interface
- public string ObtainAnswerToQuestion(string userQuestion)
- {
- string[] answers = { "Future Uncertain", "Yes", "No", "Hazy", "Ask again later", "Definitely" };
- //Return random answer.
- Random r = new Random();
- return answers[r.Next(answers.Length)];
- }
- }
- }
- </span>
3. 创建Host控制台程序,承载(寄宿)WCF Service (产品级的服务一般用Windows Service 或 IIS 虚拟目录承载)
在创建WCF Service的Host时,需要决定在代码中定义必要的承载逻辑,还是配置相关的Config文件。 配置Config文件的好处在于Host可以改变底层的运行方式而不用重新编译和部署可执行文件。
构建WCF Service的Host的一般步骤为:
(I)在Host的配置文件中,定义所承载的WCF Service 的 终结点(Endpoint)。
(II)通过编程使用ServiceHost类型去提供 Endpoint所提供的Service类型。
(III)确保Host保持运行状态,以处理所受到的客户端请求。(显然,Windows Service 或 IIS 不需要这一步 )
具体实现如下:
1)向当前项目中添加一个Application Configuration File (App.conifg). 在App.config文件中创建ABC ,
在WCF的世界中,终结点(Endpoint)是表示A(地址),B(绑定),C(契约)的一个包装。
在XML中,终结点使用<endpoint>元素,和address,binding,contract 元素进行表达。
- <span style=""><?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <services>
- <service name="Services.EightBallService">
- <endpoint address ="http://localhost:8080/EightBallService"
- binding ="basicHttpBinding"
- contract ="Contracts.IEightBall"/>
- </service>
- </services>
- </system.serviceModel>
- </configuration></span>
2)针对ServiceHost类型进行编程。创建ServiceHost实例,在运行时,这个对象会自动读取Host 中*.config文件中<system.serviceModel>元素中的数据来检测正确的地址,绑定类型和契约,然后创建必要的管道。
2.1)添加对System.ServiceModel.dll 和 本例中 Services project (即Services.dll) 的引用。
2.2)代码中引用System.ServiceModel , Services 命名空间
2.3)启用元数据交换
- 元数据交换(MEX)是一个WCF Service Behaviors,可以指定它微调WCF运行库如何处理我们的Service
- MEX行为会通过HTTP-GET拦截任何元数据请求。如果希望用svcutil.exe或者VS2010来自动创建客户端代理的*.config文件,必须启用MEX。
修改Host的App.config文件如下:
- <span style=""><?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <services>
- <service name="Services.EightBallService"
- behaviorConfiguration ="MEXBehavior">
- <endpoint address=""
- binding="basicHttpBinding"
- contract="Contracts.IEightBall"/>
- <!-- Enable MEX endpoint-->
- <endpoint address="mex"
- binding="mexHttpBinding"
- contract="IMetadataExchange"/>
- <!-- Let MEX know the address of Service-->
- <host>
- <baseAddresses>
- <add baseAddress="http://localhost:8080/Services/EightBallService"/>
- </baseAddresses>
- </host>
- </service>
- </services>
- <!-- Define behavior of MEX-->
- <behaviors>
- <serviceBehaviors>
- <behavior name="MEXBehavior">
- <serviceMetadata httpGetEnabled="true"/>
- </behavior>
- </serviceBehaviors>
- </behaviors>
- </system.serviceModel>
- </configuration>
- </span>
Host代码如下:
- <span style="">using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ServiceModel;
- using Services;
- namespace TestServiceHost
- {
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine(" Console Based WCF Host ");
- using (ServiceHost serviceHost = new ServiceHost(typeof(EightBallService)))
- {
- //Open host and keep listenning from client.
- serviceHost.Open();
- //Display host control application windows, and don't exist unless Enter key is pressed.
- Console.WriteLine(" The service is ready. Press the Enter key to terminate service. ");
- Console.ReadLine();
- }
- }
- }
- }
- </span>
运行这个应用程序后(run as administrator),宿主在内存中随时准备接受从远程客户端发来的请求。
可以用Web浏览器来查看元数据描述。http://localhost:8080/Services/EightBallService
补充1: <system.serviceModel>元素的细节
- <span style=""><system.serviceModel>
- <behaviors></behaviors> <!-- 进一步限定Host,Service或Client端的功能。-->
- <client></client> <!-- 包含客户端来连接到Service的endpoint列表。-->
- <commonBehaviors></commonBehaviors> <!-- 定义了允许WCF和COM互操作的COM契约-->
- <diagnostics></diagnostics> <!-- 包含WCF诊断特新的设置,可以启用或禁用跟踪,性能计数器,和WMI提供程序,并且可以增加自定义消息过滤器-->
- <comContracts></comContracts> <!-- 这个元素只能在machine.config文件中进行设置,可以用于定义某个机器所有的WCF的行为-->
- <services></services> <!-- 包含了从Host公开的WCF Service的集合 -->
- <bindings></bindings> <!-- 允许我们微调WCF提供的绑定如basicHttpBinding和netMsmqBing等-->
- </system.serviceModel>
- </span>
4. 创建一个控制台项目,构建WCF Client端应用程序。
1)首先需要创建客户端代理(proxy) (注:之前需要使Host程序保持运行,即使WCF Service保持运行状态)
方法一: 使用svcutil.exe 生成代理代码
svcutil http://localhost:8080/EightBallService/out:myProxy.cs /config:app.cofig
方法二: 使用VS2010生成代理代码。
1.1) 在Client控制台项目中,Add Service Reference。然后在Address里面输入Service的Uri: http://localhost:8080/EightBallService
1.2) 点击go查看Service 描述。命名为 EightBallServiceReference 后保存退出。
- 工具会自动生成客户端的代理类EightBallClient代码。
2)编写客户端控制台代码
- <span style="">using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- // Proxy location
- using Client.EightBallServiceReference;
- namespace Client
- {
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine(" Ask the Magic 8 Ball . \n");
- using (EightBallClient ball = new EightBallClient())
- {
- Console.Write("Your questoin:");
- string question = Console.ReadLine();
- string answer = ball.ObtainAnswerToQuestion(question);
- Console.WriteLine("8-ball syas:{0}", answer);
- }
- Console.ReadLine();
- }
- }
- }</span>
至此,我们在Client端运行Client.exe程序,就可以通过Service代理类来运行WCF Service 中的方法了。 实现了Client端和Server端的通信。