- 浏览: 79662 次
- 性别:
- 来自: 苏州
文章分类
最新评论
WCF的编程模型-实例: 构建一个简单的WCF应用.
- 博客分类:
- C#/.NET
WCF的编程模型-实例: 构建一个简单的WCF应用.
(注:参考 蒋金楠 著作 WCF 技术剖析 及 博客 )
本例:实现一个简单的计算服务(CalculatorService),提供加减乘除运算.
和传统的分布式通信框架一样,WCF本质上提供了一个跨进程,跨机器以致跨网路的服务调用。
在本例中,客户端和服务通过运行在相同的同一台机器上不同进程模拟,调用关系如下图:
客户端进程: 服务器端进程:(本机模拟)
Client.exe
|-------->; ( CalculatorService) Hosting.exe [Self-Hosting]
|-------->; ( CalculatorService) W3wp.exe [IIS-Hosting]
WCF的服务不能孤立地存在,需要寄宿于一个运行的进程中:
- 承载WCF服务的进程称为宿主,为服务指定宿主的过程称为服务寄宿 (service Hosting ) .
- 在我们的计算服务应用中,采用了两种服务寄宿方式:
(1) 通过自我寄宿(Self-Hosting) 的方式创建一个控制台应用作为服务的宿主. ( 寄宿进程为Hosting.exe)
(2) 通过IIS寄宿方式将服务器寄宿于IIS中(寄宿进程为IIS的工作进行W3wp.exe)
客户端通过另一个控制台应用模拟(进程为Client.exe)
Step1 :构建整个解决方案。添加如下4个项目:
* Contracts: 类库 , 定义服务契约(Service Contract) 本例中,定义ICaculator 接口.
- 引用System.serviceMode程序集
- WCF框架的绝大部分实现和API定义在该程序集中.
* Services: 类库 , 提供对WCF 服务的实现。 本例中,继承ICaculator接口,实现具体的加减乘除操作.
- 定义在该项目中的所有WCF服务实现了定义在Contract中相应的服务契约,所有Services具有对Contracts项目的引用;
* Hosting: 控制台应用,实现对定义在Services项目中的服务的寄宿. => 本例中,创建ServiceHost对象,添加一个终结点。并启动Host进程.
- 该项目需要同时引用Contracts 和 Services 两个项目和 System.ServiceMode 程序集.
* Clinet: 控制台应用,模拟服务的客户端.
- 该项目引用System.ServiceMode程序集.
Step2 : 创建服务契约.
WCF 采用基于契约的交互方式实现了服务的自治,客户端和服务端的松耦合。
WCF 包含四种类型契约:
(1)服务契约,
- 服务契约抽象了服务提供的所有操作;
- 站在消息交换的角度来看,服务契约则定义了基于服务调用的消息交换过程中,请求消息和回复消息的结构,
以及采用的消息交换模式。
(2)数据契约,
(3)消息契约
(4)错误契约。
一般地,我们通过接口的形式定义服务契约。
- WCF广泛采用基于自定义特性(Custom Attribtue)的声明式编程模式
- 我们通过在接口上应用System.ServiceModel.ServiceContractAttribute特性将一个接口定义成服务契约。
- 在应用ServiceContractAttribute特性的同时,还可以指定服务契约的名称和命名空间
- 通过应用ServiceContractAttribute特性将接口定义成服务契约之后,接口的方法成员并不能自动成为服务的操作。在此方面,WCF采用的是显式选择(Explicit Opt-in)的策略:我们须要在相应的操作方法上面显式地应用OperationContractAttribute特性。
另外,需要在Contracts类库中添加引用: .System.ServiceModel.dll (.NET程序集)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace Contracts { [ServiceContract(Name = "CalculatorService", Namespace = "http://www.WcfTest.com/")] public interface ICalculator { [OperationContract] double Add(double x, double y); [OperationContract] double Subtract(double x, double y); [OperationContract] double Multiply(double x, double y); [OperationContract] double Divide(double x, double y); } }
Step 3: 创建服务
- 当服务契约成功创建时,我们需要通过实现服务契约来创建具体的WCF服务.
- WCF服务CalculatorService定义在Services项目中,实现了服务契约接口ICalculator,实现了所有的服务操作。CalculatorService定义如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Contracts; namespace Services { public class CalculatorService:ICalculator { public double Add(double x, double y) { return x + y; } public double Subtract(double x, double y) { return x - y; } public double Multiply(double x, double y) { return x * y; } public double Divide(double x, double y) { return x / y; } } }
Step 4: 通过自我寄宿的方式寄宿服务
- WCF服务需要依存一个运行着的进程(宿主),服务寄宿就是为服务指定一个宿主的过程。
- WCF是一个基于消息的通信框架,采用基于终结点(Endpoint)的通信手段。
- 终结点由地址(Address)、绑定(Binding)和契约(Contract)三要素组成,(Endpoint = ABC )
* 地址(Address):地址决定了服务的位置,解决了服务寻址的问题,
* 绑定(Binding):绑定实现了通信的所有细节,包括网络传输、消息编码,以及其他为实现某种功能(比如安全、可靠传输、事务等)对消息进行的相应处理。WCF中具有一系列的系统
定义绑定,比如BasicHttpBinding、WsHttpBinding、NetTcpBinding等.
*契约(Contract):契约是对服务操作的抽象,也是对消息交换模式以及消息结构的定义。
- 服务寄宿的目的就是开启一个进程,为WCF 服务提供一个运行环境。通过为服务添加一个或多个终结点,使之暴露给潜给的服务消费者。服务消费者最终通过相匹配的终结点对该服务进行调用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Contracts; using Services; using System.ServiceModel; using System.ServiceModel.Description; namespace Hosting { class Program { static void Main(string[] args) { //在宿主程序中初始化 ServiceHost, 创建一个 SerivceHost 对象。 using (ServiceHost host = new ServiceHost(typeof(CalculatorService))) { //添加一个终结点。s host.AddServiceEndpoint ( typeof(ICalculator), //服务契约的类型为 ICalculator new WSHttpBinding(), //采用HttpBinding的方式. "http://127.0.0.1:9999/calculatorservice" //Http地址 ); if (host.Description.Behaviors.Find() == null) { //添加一个ServiceMetadataBehavior,并采用基于HTTP-GET的元数据获取方式。 ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; //元数据的发布地址 behavior.HttpGetUrl = new Uri("http://127.0.0.1:9999/calculatorservice/metadata"); host.Description.Behaviors.Add(behavior); } host.Opened += delegate { Console.WriteLine("CalculatorService已经启动,按任意键终止服务!"); }; // 服务寄宿 host.Open(); Console.Read(); } } } }
F6 生产解决方案后,以“管理员权限”运行Hosting.exe,弹出控制台窗口,并提示"CalculatorService已经启动,按任意键终止服务!" ( 注:Win7下没有以管理员权限运行的话,会有;HTTP 无法注册 URL http://+:9999/calculatorservice/。进程不具有此命名空间的访问权限 错误)
在地址栏输入http://127.0.0.1:9999/calculatorservice/metadata , 得到以WSDL形式体现的服务元数据。
补充:元数据:
- 服务(Service)有两种方案可以发布自己的元数据:
(1)基于HTTP-GET 协议提供元数据。
WCF 能够为服务自动提供基于HTTP-GET的元数据,但需要显示地添加服务行为(Behavior)以支持这一功能。
服务行为属于服务的本地特性,例如是否需要基于 HTTP-GET 交换元数据,就是一种服务行为。
可以通过编程方式或管理配置方式添加行为。
一旦启用了基于 HTTP-GET 的元数据交换,在浏览器中就可以通过 HTTP 基地址(如果存在)进行访问。如果一切正确,就会获得一个确认页面,告知开发者已经成功托管了服务。确
认页面与 IIS 托管无关,即使使用自托管,我们也可以使用浏览器定位服务地址
(2)使用专门的终结点(Endpoint)的方式.
Step 5: 创建客户端调用程序
- 服务被成功寄宿后,服务端便开始了服务调用请求的监听工作.
- 服务寄宿将服务描述通过元数据的形式发布出来,相应的客户端就可以获取这些元数据创建客户端程序进行服务的消费
- 当我们添加服务引用的时候,VS在内部帮我们实现元数据的获取,并借助这些元数据通过代码生成工具(SvcUtil.exe)自动生成用于服务调用的服务代理相关的代码和相应的配置 .
在运行服务寄宿程序(Hosting.exe)的情况下,点击Client项目->引用->添加服务应用.->在地址一栏输入”http://127.0.0.1:9999/calculatorservice/metadata“->前往-> 便会自动找到
CalculatorService服务,并可查看操作.
在Namespace 输入 CalculatorServiceReference后,点击OK后,会自动生成一系列的类.
- 接口:CalculatorService . 为客户端生成的服务契约的接口。
- 接口:CalculatorServiceChannel.
- 类 : CalculatorServiceClient. 从类ClinetBase继承并实现了CalculatorSerive接口的服务代理类.(Service Proxy类)
OK, 现在我们可以创建CalculatorServiceClient对象,调用服务进行操作。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using Contracts; namespace Client { class Program { static void Main(string[] args) { using (ChannelFactory channelFactory = new ChannelFactory( new WSHttpBinding(), "http://127.0.0.1:9999/calculatorservice")) { ICalculator proxy = channelFactory.CreateChannel(); using (proxy as IDisposable) { Console.WriteLine("x:{0},y:{1},x + y ={2}", 1, 2, proxy.Add(1, 2)); Console.WriteLine("x:{0},y:{1},x - y ={2}", 1, 2, proxy.Subtract(1, 2)); Console.WriteLine("x:{0},y:{1},x * y ={2}", 1, 2, proxy.Multiply(1, 2)); Console.WriteLine("x:{0},y:{1},x / y ={2}", 1, 2, proxy.Divide(1, 2)); Console.ReadLine(); //pause } } } } }
Client生成后,运行Client.exe.输出如下:
x:1,y:2,x + y =3
x:1,y:2,x - y =-1
x:1,y:2,x * y =2
x:1,y:2,x / y =0.5
实际上,还有另外一种创建服务代理的方法,就是通过ChannelFactory
在上述例子中,先移除服务引用CalculatorServiceReference. 然后添加对Contracts的引用.
Step 6: 通过IIS 寄宿服务.
Step1~5 是通过自我寄宿的方式寄宿服务。现在我们演示将WCF服务寄宿到IIS中.
包含2个步骤:
(1) 为 WCF 服务 创建.svc文件
- 在ASP.NET Web服务中有.asmx文本文件,客户端通过访问.asmx文件实现对相应Web服务的调用。
- 类似的,WCF服务中也有相应的文本文件,即.svc文件. svc文件部署在IIS站点中。
- .svc文件的内容很简单: 具有一个包含Service属性和一些可选的属性。
本例中. CalculatorService对应的.svc文件如下,并将此文件放到Services项目的根目录下.
文件命名为: CalculatorService.svc
(2) 为WCF服务 创建 IIS 虚拟目录。
- WCF服务需要在IIS下创建相应的虚拟目录。
- 本例中,直接把Services项目的根目录映射为IIS虚拟目录。(目录名:WcfServices)
- 为CalculatorService 创建配置文件,只须在Serivces的根目录下创建 Web.config.
发表评论
-
(WCF) 示例1:Magic Eight Ball.
2013-01-13 17:31 807实例一: 构建一个简 ... -
(WF) 基础1.创建一个WF4.0项目
2012-12-31 16:52 1068(WF) 基础1.创建一个WF4.0项目。 从WinF ... -
(WCF) 基础知识
2012-12-29 14:07 798SOA(Service-Oriented ... -
Visual Studio “类视图”和“对象浏览器”图标
2012-12-29 12:52 881转载: http://blog.sina.com.cn/s/b ... -
(C#)属性(property)
2012-12-25 22:39 786(C#)属性(property) 属性是字段和方法的一个交集 ... -
(C#)事件(Event)
2012-12-20 22:06 1071(C#)事件(Event) 事件好像是被简化的针 ... -
(C#)异步编程(进程,线程,计时器)
2012-12-12 12:09 1831(C#)异步编程(进程,线程,计时器) 进程 - 启动 ... -
(C#)接口(Interface)
2012-12-11 15:04 916(C#)接口(Interface)接口是 ... -
(C#)委托(delegate)
2012-12-11 11:42 679(C#)委托(delegate)委托是包含具有相同签名和返回值 ... -
(C#)枚举.
2012-12-11 10:32 636(C#)枚举. 枚举是由程序员定义的类型。- 与结构一样,枚 ... -
(C#)异常及处理.
2012-12-11 09:42 587(C#)异常及处理. 异常时程序运行时发生的错误,它违反了一 ... -
C # 基本概念 (面试题)
2012-11-22 10:37 827Interview Problem 1.Does C# s ... -
C sharp 基本概念(面试题)
2012-11-22 10:35 0Interview Problem 1.Does C# ... -
C# 基本概念(问题)
2012-11-22 10:11 1123传入某个属性的set方 ...
相关推荐
1.4.3 重用第一个windows窗体 50 1.5 visual studio 2010中的特色功能 51 1.5.1 构建配置 51 1.5.2 任务列表 53 1.5.3 command窗口 54 1.5.4 server explorer 54 1.5.5 在visual studio 2010中记录和...