wcf之旅1创建一个简单的wcf程序.docx

上传人:b****4 文档编号:24630646 上传时间:2023-05-29 格式:DOCX 页数:11 大小:23.66KB
下载 相关 举报
wcf之旅1创建一个简单的wcf程序.docx_第1页
第1页 / 共11页
wcf之旅1创建一个简单的wcf程序.docx_第2页
第2页 / 共11页
wcf之旅1创建一个简单的wcf程序.docx_第3页
第3页 / 共11页
wcf之旅1创建一个简单的wcf程序.docx_第4页
第4页 / 共11页
wcf之旅1创建一个简单的wcf程序.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

wcf之旅1创建一个简单的wcf程序.docx

《wcf之旅1创建一个简单的wcf程序.docx》由会员分享,可在线阅读,更多相关《wcf之旅1创建一个简单的wcf程序.docx(11页珍藏版)》请在冰豆网上搜索。

wcf之旅1创建一个简单的wcf程序.docx

wcf之旅1创建一个简单的wcf程序

WCF之旅

(1):

创建一个简单的WCF程序

[原创]我的WCF之旅

(1):

创建一个简单的WCF程序

写在前面

在Microsoft提出.NET战略以来,先后推出了一系列产品和技术,这些产品和技术为我们在.NET平台下建立企业级的分布式应用提供了很大的便利。

这些技术和产品包括:

.NETRemoting,XMLWebSerivce,WSE(2.0,3.0),EnterpriseService,MSMQ......

我们知道,和一个相对独立的应用不同,我们开发一个分布式应用,尤其是开发一个企业级的分布式应用,我们需要考虑较多的东西。

比如我们要考虑数据在不同的应用之间传递时采取什么样的机制,这种数据传递是否是安全的,可靠的;如何在分布式的环境下进行异常处理;如何把分别在不同应用中执行的操作纳入同一个事务……

对于我们上面提到的这些问题,这些都是开发分布式应用考虑的典型的问题。

值得庆幸的是,Microsoft开发的分布式的产品能够部分的解决这些问题。

.NETRemoting为我们在.NET平台下提供了非常好的解决方案(我个人认为,.NETRemoting是.NET平台下最为成熟的分布式技术。

比如相较于另一个使用更为广泛的技术XMLWebService,它具有一些自己独特的特性:

可以使用不同的传输层协议进行通信——Http&TCP;可以使用不同的消息编码方式——Bianry&Text(XML);可以寄宿到IIS和任何一种托管的应用下——ConsoleApplication、WinFormApplication、WindowsService……;Server端可以通过双向通信回调(Callback)客户端的操作;……)XMLWebService为使我们实现跨平台的系统能够集成显得如此简单。

随着技术的不断发展,相关的技术规范(WS-*Specification)不断完善,XMLWebService现在已经成为使用最为广泛的分布式技术了。

XMLWeb Service能够得到如此广泛的推广,这得得益于Microsoft先后两次推出的WebServiceEnhancement(WSE2.0、WSE3.0)。

如果没有WSE, 单纯的asmx下的如此的担保和不可靠。

WSE为WebService解决了几大难题:

Security、ReliableMessaging、transactionHandling以及大数据的有效传输。

 MSMQ作为一种简单而有效的机制为不同应用之间数据的传递提供了保障。

其实,通过合理利用上面这些分布式的技术完全可以为我们建立的一套适合不同层次需要的分布式构架。

但这里面仍然存在一些问题,那就是上面这些技术和产品只能解决某一方面的问题; 比如.NETRemoting虽然在.NET平台下是一个很好的依靠, 但是考虑到他不能提供不同平台之间的互操作性。

另外,这些技术适合用了完全不同的编程方式,使得我们很难从容地从其中一种转移到另一种上来。

基于这些原因, 我们需要一套全新的技术整合以上都这些技术, 于是我们有了今天的WCF——WindowsCommunicationFoundation。

WCF建立一套框架,是我们通过一致的编程模式,使用不同的技术构建我们的分布式应用。

虽然很早开始接触WCF,但所学的总是零零碎碎。

现在开始系统地研究WCF,希望与大家一同分享我的一些所得, 同时希望能通过这样的一个机会与大家一些探讨WCF,不对的地方希望大家指正。

一开始我们先建立一个简单程序看WCF如何工作:

1 建立整个应用的简单构架

整个构架如图所示,这个Solution由5个Project组成:

Artech.WCFService.Contract; Artech.WCFService.Service;Artech.WCFService.Hosting;Artech.WCFService.Client;http:

//localhost/WCFService。

Artech.WCFService.Contract:

 ClassLibraryProject,用来保存Contract(ServiceContact、MessageContract、DataContract), 之所以把Contract独立出来的原因是考虑到他同时被Server端——Service本身和ServiceHosting和Client端使用。

(现在很多的参考书,包括MSDN都使用ServiceModelMetadataUtilityTool(Svcutil.exe)这样的一个工具来访问Service的MetadataEndpoint来生成我们的客户段代码,这些代码就包括ServiceContract(一般是一个Interface),实现了这个Contract的ProxyClass(一个集成自System.ServiceModel.CientBase的一个Class)和相应的Configuration。

 这个工具确实给我提供了很大的方便。

但我不推荐使用这样的方法(我天生不倾向对于这些代码生成器),因为我觉得, 在Contract可得的情况下-比如Service和Client都是自己开发,让Service和Client实现的Contract是同一个Contract能够保证一致性。

这个Project引用System.ServiceModelDLL。

Artech.WCFService.Service:

ClassLibraryProject,Service的业务逻辑, 这个Project引用Artech.WCFService.ContractProject和System.ServiceModelDLL。

Artech.WCFService.Hosting:

ConsoleApplication, 用于以Self-Hosting的方式HostService。

这个Project引用Artech.WCFService.Contract和Artech.ProjectWCFService.Service。

Project和System.ServiceModelDLL。

Artech.WCFService.Client:

ConsoleApplication, 用以模拟现实中的调用Service的Clinet。

这个Project引用Artech.WCFService.ContractProject和System.ServiceModelDLL。

http:

//localhost/WCFService:

WebSiteProject, 用于模拟如何把ServiceHost到IIS中。

这个Project引用Artech.WCFService.Contract、Artech.WCFService.Service和System.ServiceModelDLL。

2 创建ServiceContract

在这个例子中我们建立一个简单的案例,做一个计算器, 假设我们只要求他做简单的加法运算就可以了。

在Artech.WCFService.Contract添加一个interface,名称叫做ICalculator。

usingSystem.Collections.Generic;

usingSystem.Text;

usingSystem.ServiceModel;namespaceArtech.WCFService.Contract

{

[ServiceContract]

publicinterfaceICalculator

{

[OperationContract]

doubleAdd(doublex,doubley);

}

}使一个Interface成为ServiceContract的方法很简单,就是把ServiceContractAttribute应用到这个interface上,并在代表单个Operation的方法上应用OperationContractAttribute。

这个使用CustomAttribute的编程模式被称为声明式的编程(Declarative)方式, 他在.NETFramework1.1以前用到的地方还不是太多,在.NETFramework2.0, 尤其是NETFramework3.0中,这种方式已经变得随处可见了。

我们可以把Contract定义成一个Interface,也可以把它定义到一个Class中——这个Class中既包涵Service本身又作为一个Contract而存在。

但我推荐使用第一种方法——Serive和Contract相分离。

在WCF中,Contract的功能实际上就定义一个Service包含哪些可用的Operation, 以及的每个Opertaion的方法签名。

从消息交换(MessageExchange)的角度讲,Contract定义了调用相应的Serive采取的消息交换的模式(MessageExchangePattern-MEP),我们经常使用的MEP包括三种:

Oneway, Request/Response,和Duplex。

因为调用Service的过程实际就是消息交换的过程, 以常见的Request/Response为例。

Client调用某个方面远程访问Service,所有的输入参数被封装到RequestSoapMessage并被发送到Service端, Service端监听到这个SoapRequest,创建相应的ServiceObject并调用相关的操作,最后将Result(这可以是ReturnValue,ReferenceParameter和OutputParameter)封装成SoapMessage发送回Client端。

这里需要注意,如果采用的是Request/Response的模式,即使相应的操作没有ReturnValue,ReferenceParameter和OutputParameter(它被标记为void),Service仍然会返回一个空的SoapMessage给Client端。

3 创建Service

前面我们已经创建了我的Artech.WCFService.Contract。

其实我们从Contract这个单词上讲, 它就是一种契约,一种承诺。

 他表明在上面签了字你就的履行Contract上义务。

Service就是这样一个需要履行Contract义务的人。

在这个例子中, Contract以Interface的方式定义的一些Operation。

作为Service, 在Contract上签字的方式就是实现这样的一个Interface。

 下面的Service得到code, 很简单。

usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.ServiceModel;usingArtech.WCFService.Contract;namespaceArtech.WCFService.Service{publicclassCalculatorService:

ICalculator{#regionICalculatorMemberspublicdoubleAdd(doublex,doubley){returnx+y;}#endregion}}4.HostingService

就像Remoting一样,我们继承自System.MarshalByRefObject 的对象必须Host到某一个运行的进程中, 他才开始监听来自Client端的请求,当Client才能通过Proxy远程的调用,RemotingInfrastructure监听到来自Client端的请求,他会激活相应的remoteObject(我们只考虑ServerActivateObject——SAO)。

实际上对于WCFService也需要一个Host环境才有其发挥作用的舞台。

就像Remoting一样,你可以使用任何一种ManagedApplication——ConsoleApplication、WinFormApplication、ASP.NETApplication——作为它的Host环境。

 你甚至可以用它Host到WindowsService中和IIS中(后面我将会讲到如何做)。

我们知道WCF中,Client端和Service端是通过Endpoint来通信的,Endpoint有包含3个部分,经典地称为ABC.

A代表Address,它包含一个URI,它指明Service存在于网络的某个地方,也就是说它为Client断指明在什么地方去找到这个Service。

很多人认识Address仅仅只是一个具有Identity的URI,实际上不然, Address不止于此, 它还包含一些Header,这些信息在某些情况下对于如何寻址有很大的意义(比如在client的最终Service之间还有一些Intermediary节点的情况下)。

 在.NET中, Address用System.ServiceModel.EndpointAddress 来表示。

B代表Binding,Binding封装了所有Client和Service段消息交换的通信细节。

比如他定义了通信应该采用的Transport-比如我们是因该采用Http, TCP,NamedPipe或者是MSMQ;通信的内容应该采取怎样的编码——比如是Text/XML,Binary还是MTOM。

以上这些都得一个Binding所必须定义的内容, 此外,Binding 还可以定义一些其他的有关通信的内容, 比如Security,ReliableMessaging, Session, Transaction等等。

正因为Binding对于通信的重要性,只有Service端的Binding和Client的Binding相互匹配的时候,他们之间在可以相互通信。

如何使Client Binding 匹配Service Binding呢?

最简单也是最直接的方法就是使用相同的Binding。

WCF为我们定义了一系列的SystemDefinedBinding,这些Binding在Transport,Interoperability,Security,SessionSupport,以及TransactionSupport方面各有侧重。

基本上WCF为我们定义的这些Binding 已经够我们使用的了,如果,实在满足不了要求, 你还可以建立自己的CustomBinding。

C 代表Contract这在上面已经提及,这里不再累赘。

Host的本质就是把一个Service 置于一个运行中的进程中,并以Endpoint的形式暴露出来,并开始监听来自Client端的请求。

这里值得注意的是,同一个Service可以注册若干不同的Endpoint,这样不同的Client就可以以不同的方式来访问同一个Service.比如,同一个Intranet的Client可以以TCP的方式访问Service,另一个存在已Internet中的Client则只能以Http的方式访问。

usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.ServiceModel;usingArtech.WCFService.Contract;usingArtech.WCFService.Service;usingSystem.ServiceModel.Description;namespaceArtech.WCFService.Hosting{classProgram{staticvoidMain(string[]args){HostingServiceViaCode();}staticvoidHostingServiceViaCode(){//SpecifythebaseAddressUribaseUri=newUri("http:

//localhost:

8080/calculatorService");//createanewServiceHostobjectandspecifythecorrespondingServiceandbaseAddress//Itisrecommendedtoapplytheusingpatterntomakesurethesevicehostcanbeclosedproperly.using(ServiceHostcalculatorServiceHost=newServiceHost(typeof(CalculatorService),baseUri)){//CreateaBindingforEndpoint.BasicHttpBindingBinding=newBasicHttpBinding();//CreateaServiceEndpointbyspecifytheAddress(itisabsoluteorrelativepathbasedonthebaseAddress,theemptystringindicatestheAddressequalsbaseAddress),//Binding(thebasicHttpBindingcreated)andContrace(itisnowthetypeinfoofthecontractinterface)calculatorServiceHost.AddServiceEndpoint(typeof(ICalculator),Binding,string.Empty);//SuchasegmentofcodesnipshowshowtomakethemetadataexposedtotheouterworldbysettingtheServicemetadatabehavior//FindtheServicemetadatabehaviorifexists,otherwizereturnnull.ServiceMetadataBehaviorbehavior=calculatorServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();//IftheServicemetadatabehaviorhasnottoaddedtotheService.wewillcreateanewoneandevaluatetheHttpGetEnabled&HttpGetUrltomakeouterworldcanretrievetometadata.if(behavior==null){behavior=newServiceMetadataBehavior();behavior.HttpGetEnabled=true;//HttpGetUrlisabsoluteorrelativebasedonbaseAddressbehavior.HttpGetUrl=baseUri;//Wemustaddthenewbehaviorcreatedtothebehaviorcollection,otherwizeitwillnevertakeeffect.calculatorServiceHost.Description.Behaviors.Add(behavior);}//ifthemetadatabehaviorexistsinthebehaviorcollection,wejustneedtoevaluatetheHttpGetEnabled&HttpGetUrlelse{behavior.HttpGetEnabled=true;behavior.HttpGetUrl=baseUri;}//AddtheopenedeventhandlertomakeafriendlymessagedisplayedafteropeningtheServicehostindicatingtheServicebegintolistentorequestfromClients.calculatorServiceHost.Opened+=delegate{Console.WriteLine("CalculatorServicebegintolistenviatheAddress:

{0}",calculatorServiceHost.BaseAddresses[0].ToString());};//OpentheServicehostmakeitbegintolistentotheClients.calculatorServiceHost.Open();Console.Read();}}}}

我们现在可以单独运行HostingProjet,以下是运行后的截图。

当Hosting启动之后,由于我们为它开启了HttpEnabled,Hosting为专门创建一个MetadataEndpoint,通过访问这个Endpoint,我们可获取Service相关的Metadata。

像ServiceModelMetadataUtilityTool(Svcutil.exe)这得工具就是通过获取Metadata来帮我们生成相应的客户端代码和配置文件。

当Hosting被启动之后,我们可以在IE中输入MetadataEndpoint的Address来测试Service的可访问性。

如下图。

以上我们完全以代码的方式Host一个已经创建的Service。

在这个例子中,Endpoint的所有信息都在代码中指定。

实际上真正的项目开发之中,我们基本上不采用这样的方法。

这是因为,Service的Addresss以及Binding 信息在开发阶段和部署阶段往往是不一样的。

所以我们通常的做法是把这些信息放在Config文件中,这样我们可以根据实际的需求改变存储于Config文件中的信息,比如我们把Service移植上另外的位置,我们只要改变Endpoint的Address配置信息就可以了; 再比如,我们把原来存在Intranet的Service放到Internet上,原来可能基于TCP的Binding必须改成基于Http的Binding,在这种情况下,我们依然可修改配置文件就可以了,这样的改动通常是很小的,并且修改了配置文件之后我们不需要对现有的代码进行重编译和重部署,它们可以其实生效。

下面我们来看看如何创建基于Configuration的Hosting。

首先,在Artech.WCFService.Hosting中创建App.config,并编写如下结构的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 经济学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1