as wo konw 。Net一直在分布式领域做的不好,这就使得NEt有了很大的限制。而WCF的出现必将引领着新的时代。
我学这个呢,呵呵,才俩天。不过思路是率清楚了。
WCF主要包括以下几个内容:
Artech.WCFService.Contract: Class Library Project,用来保存Contract(Service Contact、Message Contract、Data Contract), 之所以把Contract独立出来的原因是考虑到他同时被Server端——Service本身和Service Hosting和Client端使用。(现在很多的参考书,包括MSDN都使用ServiceModel Metadata Utility Tool (Svcutil.exe)这样的一个工具来访问Service的Metadata Endpoint来生成我们的客户段代码,这些代码就包括Service Contract(一般是一个Interface),实现了这个Contract的Proxy Class(一个集成自System.ServiceModel.CientBase的一个Class)和相应的Configuration。 这个工具确实给我提供了很大的方便。但我不推荐使用这样的方法(我天生不倾向对于这些代码生成器),因为我觉得, 在Contract可得的情况下-比如Service和Client都是自己开发,让Service和Client实现的Contract是同一个Contract能够保证一致性。这个Project引用System.ServiceModel DLL。Artech.WCFService.Service:Class Library Project,Service的业务逻辑, 这个Project引用Artech.WCFService.Contract Project和System.ServiceModel DLL。Artech.WCFService.Hosting:Console Application, 用于以Self-Hosting的方式Host Service。这个Project引用Artech.WCFService.Contract和Artech. Project WCFService.Service。Project和System.ServiceModel DLL。Artech.WCFService.Client:Console Application, 用以模拟现实中的调用Service的Clinet。这个Project引用Artech.WCFService.Contract Project 和System.ServiceModel DLL。http://localhost/WCFService: Web Site Project, 用于模拟如何把Service Host到IIS中。这个Project引用Artech.WCFService.Contract、Artech.WCFService.Service和System.ServiceModel DLL。 2 创建Service Contract在这个例子中我们建立一个简单的案例,做一个计算器, 假设我们只要求他做简单的加法运算就可以了。在Artech.WCFService.Contract添加一个
interface,名称叫做ICalculator。使一个Interface成为Service Contract的方法很简单,就是把ServiceContractAttribute应用到这个interface上,并在代表单个Operation的方法上应用OperationContractAttribute。这个使用Custom Attribute的编程模式被称为声明式的编程(Declarative)方式, 他在.NET Framework 1.1以前用到的地方还不是太多,在.NET Framework 2.0, 尤其是NET Framework 3.0中,这种方式已经变得随处可见了。我们可以把Contract定义成一个Interface,也可以把它定义到一个Class中——这个Class中既包涵Service本身又作为一个Contract而存在。但我推荐使用第一种方法——Serive和Contract相分离。在WCF中,Contract的功能实际上就定义一个Service包含哪些可用的Operation, 以及的每个Opertaion的方法签名。从消息交换(Message Exchange)的角度讲,Contract定义了调用相应的Serive采取的消息交换的模式(Message Exchange Pattern - MEP),我们经常使用的MEP包括三种:Oneway, Request/Response,和Duplex。因为调用Service的过程实际就是消息交换的过程, 以常见的Request/Response为例。Client调用某个方面远程访问Service,所有的输入参数被封装到Request Soap Message并被发送到Service端, Service端监听到这个Soap Request,创建相应的Service Object并调用相关的操作,最后将Result(这可以是Return Value,Reference Parameter和Output Parameter)封装成Soap Message发送回Client端。这里需要注意,如果采用的是Request/Response的模式,即使相应的操作没有Return Value,Reference Parameter和Output Parameter(它被标记为void),Service仍然会返回一个空的Soap Message给Client端。3 创建Service前面我们已经创建了我的Artech.WCFService.Contract。其实我们从Contract这个单词上讲, 它就是一种契约,一种承诺。 他表明在上面签了字你就的履行Contract上义务。Service就是这样一个需要履行Contract义务的人。在这个例子中, Contract以Interface的方式定义的一些Operation。作为Service, 在Contract上签字的方式就是实现这样的一个Interface。 下面的Service得到code, 很简单。
using
System.Collections.Generic;
using
System.Text;
using
System.ServiceModel;
namespace
Artech.WCFService.Contract
{
[ServiceContract]
public
interface
ICalculator
{
[OperationContract]
double
Add(
double
x,
double
y);
}
}
using4.Hosting Service就像Remoting一样,我们继承自System.MarshalByRefObject 的对象必须Host到某一个运行的进程中, 他才开始监听来自Client端的请求,当Client才能通过Proxy远程的调用,Remoting Infrastructure监听到来自Client端的请求,他会激活相应的remote Object(我们只考虑Server Activate Object——SAO)。实际上对于WCF Service也需要一个Host环境才有其发挥作用的舞台。就像Remoting一样,你可以使用任何一种Managed Application——Console Application、WinForm Application、ASP.NET Application——作为它的Host环境。 你甚至可以用它Host到Windows Service中和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,Named Pipe或者是MSMQ;通信的内容应该采取怎样的编码——比如是Text/XML,Binary还是MTOM。以上这些都得一个Binding所必须定义的内容, 此外,Binding 还可以定义一些其他的有关通信的内容, 比如Security,Reliable Messaging, Session, Transaction等等。正因为Binding对于通信的重要性,只有Service端的Binding和Client的Binding相互匹配的时候,他们之间在可以相互通信。如何使Client Binding 匹配Service Binding呢?最简单也是最直接的方法就是使用相同的Binding。WCF为我们定义了一系列的System Defined Binding,这些Binding在Transport,Interoperability,Security,Session Support,以及Transaction Support方面各有侧重。基本上WCF为我们定义的这些Binding 已经够我们使用的了,如果,实在满足不了要求, 你还可以建立自己的Custom Binding。C 代表Contract这在上面已经提及,这里不再累赘。Host的本质就是把一个Service 置于一个运行中的进程中,并以Endpoint的形式暴露出来,并开始监听来自Client端的请求。这里值得注意的是,同一个Service可以注册若干不同的Endpoint,这样不同的Client就可以以不同的方式来访问同一个Service.比如,同一个Intranet的Client可以以TCP的方式访问Service,另一个存在已Internet中的Client则只能以Http的方式访问。
System;
using
System.Collections.Generic;
using
System.Text;
using
System.ServiceModel;
using
Artech.WCFService.Contract;
namespace
Artech.WCFService.Service
{
public
class
CalculatorService:ICalculator
{
#region
ICalculator Members
public
double
Add(
double
x,
double
y)
{
return
x
+
y;
}
#endregion
}
}
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.ServiceModel;
using
Artech.WCFService.Contract;
using
Artech.WCFService.Service;
using
System.ServiceModel.Description;
namespace
Artech.WCFService.Hosting
{
class
Program
{
static
void
Main(
string
[] args)
{
HostingServiceViaCode();
}
static
void
HostingServiceViaCode()
{
//
Specify the base Address
Uri baseUri
=
new
Uri(
"
http://localhost:8080/calculatorService
"
);
//
create a new ServiceHost object and specify the corresponding Service and base Address
//
It is recommended to apply the using pattern to make sure the sevice host can be closed properly.
using
(ServiceHost calculatorServiceHost
=
new
ServiceHost(
typeof
(CalculatorService), baseUri))
{
//
Create a Binding for Endpoint.
BasicHttpBinding Binding
=
new
BasicHttpBinding();
//
Create a Service Endpoint by specify the Address(it is absolute or relative path based on the base Address, the empty string indicates the Address equals base Address),
//
Binding(the basicHttpBinding created) and Contrace(it is now the type info of the contract interface)
calculatorServiceHost.AddServiceEndpoint(
typeof
(ICalculator), Binding,
string
.Empty);
//
Such a segment of code snip shows how to make the metadata exposed to the outer world by setting the Service metadata behavior
//
Find the Service metadata behavior if exists, otherwize return null.
ServiceMetadataBehavior behavior
=
calculatorServiceHost.Description.Behaviors.Find
<
ServiceMetadataBehavior
>
();
//
If the Service metadata behavior has not to added to the Service. we will create a new one and eval(behavior
==
null
)
{
behavior
=
new
ServiceMetadataBehavior();
behavior.HttpGetEnabled
=
true
;
//
HttpGetUrl is absolute or relative based on base Address
behavior.HttpGetUrl
=
baseUri;
//
We must add the new behavior created to the behavior collection, otherwize it will never take effect.
calculatorServiceHost.Description.Behaviors.Add(behavior);
}
//
if the metadata behavior exists in the behavior collection, we just need to eval(
"
Calculator Service begin to listen via the Address:{0}
"
, calculatorServiceHost.BaseAddresses[
0
].ToString()); };
//
Open the Service host make it begin to listen to the Clients.
calculatorServiceHost.Open();
Console.Read();
}
}
}
}