Wcf应用基础.docx
《Wcf应用基础.docx》由会员分享,可在线阅读,更多相关《Wcf应用基础.docx(147页珍藏版)》请在冰豆网上搜索。
Wcf应用基础
目录
第八章分布式系统(WCF)基础2
8.1什么是WCF2
8.2Hello,World实例3
8.2.1创建WCF服务端程序3
8.2.2创建WCF客户端程序6
8.2.3在客户端添加WCF引用7
8.2.4调用WCF服务8
8.2实体类应用实例10
8.2.1建立契约项目10
8.2.2建立学生实体类11
8.2.3建立实体服务契约13
8.2.4建立WCF服务代理14
8.2.5建立WCF服务项目18
8.2.6添加服务契约层引用19
8.2.7实现WCF服务契约(实现服务接口)19
8.2.8测试WCF服务21
8.2.9建立用户界面项目22
8.2.10调用WCF服务23
8.3知识讲解26
8.3.1WCF是怎么运行的?
26
8.3.2WCF绑定27
8.3.3契约27
8.3.4序列化29
8.3.5WCF宿主32
8.3.6自我跟踪(Self-Tracking)32
8.4学生信息管理系统实例33
8.4.1项目层次架构介绍35
8.4.2页面功能介绍35
8.4.3数据库设计36
8.4.4建立实体层39
8.4.5建立自我跟踪层43
8.4.6建立公共契约层46
8.4.7建立WCF服务层54
8.4.8建立Web应用层64
8.4.9建立系统皮肤65
8.4.10修改母版页67
8.4.11配置WCF访问地址69
8.4.12学生列表页面70
8.4.13学生信息编辑页面75
8.4.14学生详细信息页面95
8.4.15学生教育经历列表页面104
8.4.15编辑学生教育经历页面112
第八章分布式系统(WCF)基础
软件开发经历了面向过程,面向对象,面向组件,现今,面向服务(SOA)开发已风靡整个软件开发领域,是否掌握分布式开发是衡量一个软件工程师的重要标准之一。
通过本章的学习,我们能掌握面向服务开发(SOAP)的基本原理和相关应用。
我们精心安排了三个精典案例,在实例中穿插了知识点以便辅助大家学习、理解:
第一个例子介绍如何在控制台中应用WCF,实例讲解客户端如何访问WCF,如何获取服务器端的返回值。
目的在于引导大家入门,为掌握WCF应用建立感性认识。
第二个例子介绍如何在ASP.Net应用程序中应用WCF,实例讲解客户端如何与服务器进行数据交互。
目的在于了解WCF的基本概念,并在相关知识点处作详细讲解,通过这个实例,我们将掌握WCF的基础知识。
本章要点
WCF的概念
WCF绑定
WCF契约
序列化
WCF宿主
实体自我跟踪
8.1什么是WCF
从WCF所处的位置来看,它是包含在.NET3.0(也包括.NET3.5)之中的。
我们注意比较.NET3.0与.NET2.0,其实唯一的区别就是.NET3.0包含了WCF(WindowsCommunicationFundation)、WPF(WindowsPresentationFundation)、WF(WindowsWorkFlowFundation,或者还有CardSpace)而已。
因此,我们认为WCF是.NET框架的一部分。
尤为关键的是,WCF并不能脱离.NET框架而单独存在(非WCF客户端也可以调用WCF服务)。
因此,虽然WCF是微软用以应对SOA解决方案的开发需求而专门推出的,但它并不是例如Spring、Struts那样的框架,也不是像EJB那样的容器或者服务器。
严格的说,WCF就是专门用于服务定制、发布与运行以及消息传递和处理的一组专门类的集合,也就是所谓的“类库”。
这些类通过一定方式被组织起来,共同协作,并为开发者提供了一个统一的编程模式。
WCF之所以特殊,是在于它所应对的场景与普通的.NET类库不同,它主要用于处理进程间乃至于机器之间消息的传递与处理,同时它引入了SOA(Service-OrientedArchitecture,即面向服务架构)的设计思想,以服务的方式公布并运行,以方便客户端跨进程和机器对服务进行调用。
实际上,WCF就是微软对于分布式处理的编程技术的集成者,它将DCOM(DistributedComponentObjectModel)、Remoting、WebService、WSE(WebServicesEnhancements)、MSMQ(MicroSoftMessageQueue)集成在一起,从而降低了分布式系统开发者的学习曲线,统一了开发标准,并且获得了较好的性能改进。
WCF与其它类库还有不同的地方,在于WCF充分地体现了运行时环境的概念。
对于早期使用WCF的开发人员而言,就可能知道如果在.NET2.0下要开发WCF,还需要专门下载一个RuntimeComponent3.0版,其中就包含了WCF、WF等内容。
在.NET中一贯存在所谓“宿主”的概念,整个.NETFramework(或者说是CLR)就可以认为是一个大的宿主,就像Java的虚拟机一样。
由于WCF对服务有着专门的需求,对于服务端,需要发布和运行服务;对于客户端,则需要调用服务;因而对于开发者,就需要编写定义、发布、运行、调用服务的相关代码。
而服务就只能运行在特定的宿主上,这些宿主可以是控制台应用程序进程、Windows或Web应用程序进程,也可以是Windows服务进程,或者最常用的IIS宿主。
在宿主内部,则封装了通道堆栈,其中又包含了对协议、编码、消息传输、代理的处理。
而在通道层的顶部,还提供了一个高级运行时,以针对应用程序的开发人员。
我们将以一个“Hello,World实例”开始,辅以相关基础知识点,初窥WCF。
8.2Hello,World实例
本实例与传统入门教材相同,仍然以输出一个“Hello,World”字符串开始。
实例将新建2个项目,第一个项目名为“HelloWorldService”,它提供WCF服务,并且以开发环境方式暴露一个端口供客户端调用;另外一个项目叫“HelloWorldClient”,它调用WCF服务方法,并输出返回值。
本实例的运行结果如图所示:
8.2.1创建WCF服务端程序
1)打开MicrosoftVisualStudio2010;
2)选择菜单>文件>新建>项目;
3)在弹出的“新建项目”对话框中展开左边的“已安装的模板”>VisualC#;
4)选择“WCF”;
5)在对话框右边选择“WCFServiceApplication“;
6)在对话框下部的“项目名“中输入”HelloWorldService“,在位置中输入”d:
\Exercise“,在解决方案名称输入”WcfSample“,确保选中”Createdirectoryforsolution“,确保未选中”Addtosourcecontrol“,设置后的界面如下:
7)点击“OK“按钮,VS2010已自动建立了一个WCFServiceApplication,并且为我们自动打开了Service1.svc.cs文件;
8)打开“SolutionExplorer”;(VS2010默认打开,位置在VS2010桌面的右边,如果VS2010没有打开,请使用快捷键Ctrl+W,S打开)
9)在“SolutionExplorer”中展开“HelloWorldService”;
10)双击“IService1.cs”文件;
11)用下面的代码
///
///提供一个WCF服务方法
///
///返回“Hello,World!
”
[OperationContract]//声明为“OperationContract”的方法将暴露在WCF服务器上
stringGetHelloWorld();
替换第22行的注释
//TODO:
Addyourserviceoperationshere
知识点:
“ServiceContract”代表服务契约,表示IService1接口是一个WCF服务,这样,客户端就可以访问这个接口和它内部有效的方法了。
“OperationContract”代表操作契约,表示GetHelloWorld方法是服务契约中的一个方法,只有声明为“OperationContract”的方法才会被公开在WCF服务中。
如果服务中没有任何一个方法声明为“OperationContract”,那么这个服务将没有任何意义。
12)右键点击HelloWorldService项目,在弹出的菜单中选择“Build”,VS2010会在“ErrorList”中提示“Error1'HelloWorldService.Service1'doesnotimplementinterfacemember'HelloWorldService.IService1.GetHelloWorld()'d:
\Exercise\WcfSample\HelloWorldService\Service1.svc.cs1218HelloWorldService”;
13)在“ErrorList”对话框中双击错误项,系统会自动打开“Service1.svc.cs”文件;
14)在打开的“Service1.svc.cs”文件中选择“IService1”并右击;
15)在弹出的右键菜单中选择“ImplementInterface“>”ImplementInterface“,VS2010会自动在文件后面生成如下代码:
publicstringGetHelloWorld()
{
thrownewNotImplementedException();
}
16)用
return"Hello,World!
";
替换
thrownewNotImplementedException();
17)重复第12步,VS2010将不会报任何编译时错误了;
18)选择“HelloWorldService“项目并右击,在弹出的菜单中选择”Properties“,系统会展示项目属性界面,如下图:
19)选择左边“Web“项,在右边展示的选择中选择“Service”>“UseVisualStudioDevelopmentServer”>“Specificport”;
20)在“Specificport“后面的文本框中输入“2027”,设置正确的界面如下:
21)展开“HelloWorldService”项目;
22)选择“Service1.svc“文件并右击,在弹出的菜单中选择“ViewinBrowser”,如果正确的话,应在浏览器中出现如下界面:
23)如此,服务器端已完成了;
8.2.2创建WCF客户端程序
服务器端的服务写好了,我们再来了解客户端是如何调用的。
1)打开上一节创建的WcfSample解决方案;
2)右击解决方案WcfSample;
3)在弹出菜单中选择“Add”>“NewProject”;
4)在弹出的“AddNewProject”对话框中左边展开“InstalledTemplates”;
5)选择“VisualC#”,并在对话框可边选择“ConsoleApplication”;
6)在对话框下部的“Name”中输入“HelloWorldClient”,并且中“Location”中输入“D:
\Exercise\WcfSample”,界面如下:
7)点击“OK”按钮,VS2010会自动在“WcfSample”解决方案下生成HelloWorldClient项目;
8)到此,WCF客户端就创建好了;
8.2.3在客户端添加WCF引用
在开始前,请重复第一节(创建WCF服务端程序)第18步至22步,运行WCF服务(请确保运行正常)。
1)打开WcfSample解决方案;
2)展开HelloWorldClient项目;
3)右击“References”,在弹出的菜单中选择“AddServiceReferences…”;
4)在弹出的对话框的“Address”中输入WCF服务地址“http:
//localhost:
2027/Service1.svc”(也许您的WCF运行地址不相同,请输入您的正确地址)
5)点击“Go”按钮,系统会自动展示WCF服务端的相关服务接口;
6)在对话框的下部的“Namespace:
”中输入“HelloWorldService”,完整的界面如下;
7)点击“OK”按钮完成添加引用操作,系统会自动在“HelloWorldClient”项目下添加“ServiceReferences”文件夹,并添加了关于“HelloWorldService”的引用,如图:
8)至此,WCF引用就添加完了;
8.2.4调用WCF服务
准备工作已经完成,下面我们来看看如何调用WCF提供的GetHelloWorld方法呢。
步骤如下:
1)打开WcfSample解决方案;
2)展开“WcfSample”>“HelloWorldClient”,双击打开“Program.cs”文件,系统将展示大家熟悉的界面:
3)在Main方法中添加如下代码:
//实例化一个WCF代理对象
Service1Clientclient=newService1Client();
//获取从WCF服务方法返回的值
stringresult=client.GetHelloWorld();
//将GetHelloWorld方法返回值输出到屏幕
Console.WriteLine(result);
4)如果“Program.cs”文件没有添加对“HelloWorldClient.HelloWorldService”的引用,请在“Program.cs”文件的引用代码块的最后一行加入如下代码:
usingHelloWorldClient.HelloWorldService;
5)右击“HelloWorldClient”,在弹出菜单中选择“SetasStartupProject”将其设置为启动项目;
6)按Ctrl+F5运行程序,运行界面如下:
7)如此,本实例已全部完成了。
8.2实体类应用实例
本实例讲解WCF在Web应用程序上的应用,实例以一个实体类作为引子,WCF服务提供2个方法(根据编号获取学生信息和获取所有学生信息)并且将它们暴露在WCF服务上,以便客户端面访问。
实例将整个应用为三个层次,
共同契约层,我们知道,WCF服务器端和客户端必须遵循相同的数据契约才能进行数据交换,为了达到这一目的,我们经常在项目中独立一个单独的项目来定义其它层都必须遵守的数据结构约定。
共同契约层是其它项目共同依赖的对象,根据面向对象设计原则(依赖倒置原则),为了将各个层次合理解耦获得“高内聚,低耦合”,于是我们将其抽象为接口。
实体服务层,WCF服务提供者,它提供了WCF服务(公开了操作方法)并将其宿主到IIS中,以供其它项目或系统调用。
用户界面层,将数据WCF服务层读取出来展示到界面上。
8.2.1建立契约项目
1)打开VS2010,
2)点击菜单“File”>“New”>“Project”,在弹出的对话框中设置如下图:
3)点击“OK”按钮完成;
8.2.2建立学生实体类
1)右击“EntitySample.Common”,在弹出的菜单中选择“Add”>“NewItem…”,在弹出的对话框中设置如下:
2)点击“Add”按钮;
3)打开新建的“Student.cs”文件,将下面的代码覆盖原有代码:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Runtime.Serialization;
namespaceEntitySample.Common
{
[DataContract]
publicclassStudent
{
///
///编号
///
[DataMember]
publicintID
{get;set;}
///
///学生姓名
///
[DataMember]
publicstringStudentName
{get;set;}
///
///学生年龄
///
[DataMember]
publicintAge
{get;set;}
///
///身份证号码,没有“DataMember”标识,不能在WCF服务上公开
///
publicstringIdentification
{get;set;}
}
}
知识点:
(1)“DataContract”Attrbute代表数据契约,标识有“DataContract”的类才会被序列化,才能在网络上进行数据传输;
(2)标识有“DataMember”的属性说明它会被WCF序列化,客户端才能够取得它的属性值;
(3)请注意Identification属性,它没有被标识为“DataMember”,那么它将不会被序列化,也就是说WCF客户端将不能获得它的值(实例最后会展示实验结果);
8.2.3建立实体服务契约
1)右击“EntitySample.Common”,在弹出的菜单中选择“Add”>“NewItem…”,在弹出的对话框中设置如下:
2)点击“Add”按钮完成添加文件;
3)打开“IEntityService.cs”文件,用下面的代码覆盖原有内容:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.ServiceModel;
namespaceEntitySample.Common
{
[ServiceContract]
publicinterfaceIEntityService
{
///
///根据编号(ID)获取学生信息
///
///编号
///学生实体
[OperationContract]
StudentGetStudentByID(intid);
///
///获取所有学生信息
///
///
[OperationContract]
IListGetAllStudent();
}
}
知识点:
(1)我们在“IEntityService.cs”文件中定义了二个操作契约,其中GetStudentByID方法完成“根据ID获取学生信息”的功能,将查找到的学生实体返回;而“GetAllStudent”方法将返回所有的学生信息到客户端;
(2)IEntityService接口将会被接下来的2个项目(EntitySample.Service和EntitySample.Web)引用。
它是引用者的依赖项,因为它的变更会引起依赖项变更;
8.2.4建立WCF服务代理
1)下面我们介绍如何使用代码建立WCF代理,使得Web客户端实现对WCF服务的调用;
2)右击“EntitySample.Common”,在弹出的菜单中选择“Add”>“NewItem…”,在弹出的对话框中设置如下:
3)点击“Add”按钮;
4)用下面的代码覆盖原有代码:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.ServiceModel;
namespaceEntitySample.Common
{
publicstaticclassServiceProxyFactory
{
//WCF服务的地址
privatestaticstringTestServiceURL="";
///
///根据WCF服务的地址获取服务代理
///
///服务接口契约
///WCF服务地址
///关于服务契约的通道实例
privatestaticTGetServiceProxy(stringserviceAddress)
{
//获取BasicHttpBinding实例
varbinding=GetBasicHttpBinding();
//实例化终结点
EndpointAddressaddress=newEndpointAddress(serviceAddress);
//创建一个关于终结点的BasicHttpBinding通道工厂
ChannelFactoryfactory=newChannelFactory(binding,address);
//创建一个关于服务接口契约的通道
Tchannel=factory.CreateChannel();
//返回通道
returnchannel;
}
///
///实例化一个BasicHttpBinding
///
///实例化的BasicHttpBinding
privatestaticBasicHttpBindingGetBasicHttpBinding()
{
//实例化一个BasicHttpBinding
varbinding=newBasicHttpBinding();
//设置访问权限为"None"
binding.Security.Mode=BasicHttpSecurityMode.None;
//设置最在接收消息长度
binding.MaxReceivedMessageSize=int.MaxValue;
//设置BasicHttpBinding的SOAP复杂度的最大值,这样可以保护对终结点资源的访问层次
binding.ReaderQuotas.MaxArrayLength=int.MaxValue;
//设置