HTML5技术

快速入门系列--WCF--01基础概念 - 熊二哥(2)

字号+ 作者:熊二哥 来源:博客园 2016-02-25 19:53 我要评论( )

本节将介绍URI、端口共享、请求监听和消息分发等概念。正如之前所说的,WCF服务是通过终结点EndPoint发布,而终结点由地址、绑定和契约三要素组成,其中地址用于定位服务,并提供额外的寻址信息和认证信息。既然是

本节将介绍URI、端口共享、请求监听和消息分发等概念。正如之前所说的,WCF服务是通过终结点EndPoint发布,而终结点由地址、绑定和契约三要素组成,其中地址用于定位服务,并提供额外的寻址信息和认证信息。既然是服务定位,首先引入URI的概念,URI的全称为Uniform Resource Identifier统一资源标识,其形式是,[Schema传输协议]://[主机名|域名|IP地址]:[端口号]/[资源路经],其中支持的协议类型如下表所示。

协议类型

解释

HTTP/HTTP

前者是互联网时代的核心--超文本传输协议,其是建立在TCP/IP协议簇上应用层协议。特点无状态、无连接、提供简单请求-回复消息传输方式;后者是采用了SSL(TLS)的HTTP,提供数据加密,实际上,大部分主流网站已实现全站HTTPS。

Net.TCP

TCP全称传输控制协议,属于传输层协议,基于网络层IP协议,是应用层HTTP协议的基础。其特点是有状态、支持全双工、支持可靠通信,其是基于连接的协议,在数据传输前通过3次"握手"创建连接,在传输结束后,通过4次"握手"终止连接。

Net.Pipe

命名管道是Windows等操作系统实现跨进程通信(Inter Process Communication, IPC)的标准实现方式,虽然命名管道本身可以跨机器通信,不过WCF中的命名管道专注于同一台机器中的跨进程通信,因此其主机名为localhost,此外由于基于同一台机器,端口变得没有意义。

Net.Msmq

消息队列提供了支持离线的通信机制,其包括公共消息队列和私有消息队列两种方式,前者需要注册到AD域中。此外,除了存储业务数据消息的普通队列之外,还有存储消息拷贝的日志队列、存储确认消息的管理队列、存储回复消息的回复队列和存储死信消息的死信队列等。

其URI格式为: net.msmq://sory.com/private/xxxservice

 

之前提及的核心概念终结点在WCF中,通过System.ServiceModel.Description.ServiceEndpoint类表示,其包括Address、Binding、Contract三个核心属性。其中的Address是EndpointAddress的实现类,其包含UriHeaders、Identity三个属性,Uri即是服务的唯一标识,也是服务的目标地址,且这个地址可以使物理的,也可以是逻辑的。这儿的Headers其实就是SOAP消息中的消息头(类似于Http协议的,也包括消息头和消息体,前者主要提供一些控制信息,后者存放数据部分),它默认通过DataContractSerializer进行序列化和反序列化,最终转化为SOAP消息的MessageHeader,相应配置如下所示,添加了服务端消息头后,在客户端也需要增加相应消息头,否则会被地址过滤器给过滤掉(之后的客户端通过ChannelFactory调用服务的示例中可以看到)。

复制代码
1 <endpoint address="http://127.0.0.1:9901/addservice" binding="wsHttpBinding" contract="Sory.Entertainment.WCF.IAddService">
2 <headers>
3 <authentication xmlns="http://www.sory.com/">{12345678}</authentication>
4 </headers>
5 </endpoint>
复制代码

补充一点的是,可以通过将服务的ServiceBehavior特性中的AddressFilterModel属性设置为Any,跳过消息头的检验。

 

在基础概念一节的代码示例中,可以看到WCF通过ServiceHost完成服务寄宿,其中通过AddServiceEndpoint实现终结点的添加,当然也可以通过配置文件的方式添加终结点,在配置文件的<system.serviceModel>模块的<service>子节点中添加<endpoint>,并补全address、binding、contract属性,注意在IIS寄宿的情况下,无需提供address,因为.svc文件的地址就是服务的地址。同时,可以通过ServiceHost的Description属性(.NET中习惯使用Description获取元数据相关信息,无论是哪一种框架)获取终结点和服务行为的相关信息。

此外,除了使用绝对地址来指定某个服务的终结点地址外,还可以通过"基地址+相对地址"的方式,其配置形式如下,需要注意一种类型的协议只能有一个基地址,并且当一个服务实现类同时实现了多个服务接口时,该终结点地址可以共享。

复制代码
1 <service name="XXX" behaviorConfiguration="XXX">
2 <host>
3 <baseAddresses>
4 <add baseAddress="net.tcp://127.0.0.1/baseservice"/>
5 </baseAddresses>
6 </host>
7 </service>
复制代码

客户端通过服务代理实现对服务的调用,包括两种方式:通过服务引用或者借助SvcUtil.exe工具来生成服务代理类,该生成类继承自ClientBase<TChannel>;直接通过ChannelFactory<TChannel>创建服务代理。前者比较简单,只需要在<system.serviceModel>的子节点<client>中添加对应的<endpoint>节点,然后直接生成的对应的Client类即可,后者如下所示。

复制代码
 1 var uri = new Uri("http://127.0.0.1:9901/addservice");
 2 var header = AddressHeader.CreateAddressHeader("authentication", "http://www.sory.com/", "{12345678}");
 3 var address = new EndpointAddress(uri, header);
 4 var binding = new WSHttpBinding();
 5 var contract = ContractDescription.GetContract(typeof(IAddService));
 6  
 7 var endpoint = new ServiceEndpoint(contract, binding, address);
 8 using (var factory = new ChannelFactory<IAddService>(endpoint))
 9 {
10 var channel = factory.CreateChannel();
11 var result = channel.Add(new CompositeType { PartA = 1, PartB = "Hello, " }, new CompositeType { PartA = 2, PartB = "World!" });
12 Console.WriteLine(string.Format("PartA: {0}, PartB: {1}", result.PartA, result.PartB));
13 }
复制代码
  • 端口共享

在Windows系统,为了安全,常常只开发少量端口,当有大量应用需要使用不同端口时,会显得捉襟见肘,因此多个应用共享同一个端口显得很有必要。对于Http/Https协议来说,由于其可以通过IIS来管理应用,其自身通过HTTP.SYS已经实现了80|443端口的共享。而对于TCP协议来说,其通过一个Windows服务(名称为Net.Tcp Port Sharing Service)来管理,可以通过如下方式实现其共享。

1 <bindings>
2 <netTcpBinding>
3 <binding name="portSharingBinding" portSharingEnabled="true"></binding>
4 </netTcpBinding>
5 </bindings>
  • 逻辑地址和物理地址

之前在EndpointAddress中提及的Uri属性表示服务的逻辑地址,而物理地址对于服务端来说是监听地址,对于客户端来说是消息真正发送的目标地址。默认情况下,两个地址是统一的,但在需要中介进行消息转发的场景下,需要将两者分离。

对于服务端,可以设置终结点的ListenUri的属性和ListenUriMode属性(包括Explicit和Unique,前者严格使用ListenUri作为最终的监听地址,后者将通过不同的策略保证监听地址的唯一性,如针对端口共享的情况,将在默认Uri后加GUID以作识别),共同完成该需求,示例如下。

示例如下。

<endpoint address="http://127.0.0.1:9901/addservice" listenUri="http://127.0.0.1:9900/addservice" listenUriMode="Unique"/>

对于客户端,需要借助ClientViaBehavior这一终结点行为来实现,示例如下。

复制代码
 1 <behaviors>
 2 <endpointBehaviors>
 3 <behavior name="clientViaBehavior">
 4 <clientVia viaUri="http://127.0.0.1:9900/addservice"/>
 5 </behavior>
 6 </endpointBehaviors>
 7 </behaviors>
 8 <client >
 9 <endpoint behaviorConfiguration="clientViaBehavior"></endpoint>
10 </client>
复制代码

补充:行为这个概念在WCF中非常的重要,很多的功能都是通过相应的行为实现的,接下来进行简要介绍。如果说契约是客户端和服务端达成的某种共识,是双边协议,而行为则是客户端或服务端在本地实现某个功能的一种方式,是一种单边行为。WCF提供了4种类型的行为,包括服务行为、契约行为、终结点行为和操作行为,它们一般可以通过特性或者配置文件的方式进行设置。

 

  • 请求监听和消息分发

这部分内容涉及到整个WCF服务端的架构,下图展示了一个最简单的请求分发过程。

在整个消息监听和分发体系中,信道分发器和终结点分发器是两个核心的对象,前者负责请求监听、消息接收并通过消息筛选器选择正确的终结点,后者完成消息的处理。终结点分发器具有两个消息消息筛选器,分别是AddressFilter和ContractFilter,均是MessageFilter类型,前者对应的AddressFilterMode包含Exact、Prefix、Any三种枚举类型。WCF提供6种典型的消息筛选器,包括:ActionMessageFilter,判断请求消息(SOAP)的<Action>报头是否和终结点契约中任意操作的Action属性相匹配(Match);EndpointAddressMessageFilter判断<To>报头是否和终结点地址相匹配;MatchAllMessageFilter,表示全匹配;以及不常用的XPathMessageFilter、MatchNoneMeesageFilter和PrefixEndpointAddressMessageFilter。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 如何快速处理线上故障 - 倒骑的驴

    如何快速处理线上故障 - 倒骑的驴

    2017-05-02 12:01

  • HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    2017-05-02 11:02

  • 【Vue 入门】使用 Vue2 开发一个展示项目列表的应用 - zhangjk

    【Vue 入门】使用 Vue2 开发一个展示项目列表的应用 - zhangjk

    2017-04-30 16:00

  • JS组件系列——自己动手封装bootstrap-treegrid组件 - 懒得安分

    JS组件系列——自己动手封装bootstrap-treegrid组件 - 懒得安分

    2017-04-28 14:02

网友点评