您的位置:首页 > 其它

WCF后传系列(5):深入WCF寻址Part 5—逻辑地址和物理地址

2008-10-31 00:16 609 查看

概述

在WCF中,每个服务终结点都与两个地址相关联,一个逻辑地址和一个物理地址,逻辑地址就是SOAP消息的目标地址,即前面不止一次提到的“To”地址,而物理地址是WCF侦听器真正监听的地址。在WCF中,逻辑地址称之为终结点地址Endpoint Address,而物理地址则称之为监听地址ListenUri。
本文将详细介绍WCF中的物理地址和逻辑地址,以及如何使用tcpTrace来进行SOAP消息的跟踪。

两种地址

WCF中,物理地址负责使用特定的传输协议在特定的位置接收传入的消息,除非特别指定,否则逻辑地址将被用来做物理地址,换句话说,在以前我们对于终结点所配置的EndpointAddress都是指定了逻辑地址,如我们的服务端配置如下:
<endpoint address="http://localhost:8887/CalculatorService1"
binding ="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator">
</endpoint>
<endpoint address="http://localhost:8887/CalculatorService2"
binding ="basicHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator">
</endpoint>

现在我们输出一下,就可以看到两个地址是同样的值,如下代码所示:
using (ServiceHost calculatorServiceHost =
new ServiceHost(typeof(CalculatorService)))
{
calculatorServiceHost.Opened += delegate
{
Console.WriteLine("Service begin to listen via the Address:{0}",
calculatorServiceHost.BaseAddresses[0].ToString());
};
calculatorServiceHost.Open();
foreach (ServiceEndpoint se in calculatorServiceHost.Description.Endpoints)
{
Console.WriteLine("Endpoint details:");
Console.WriteLine("Logical address: \t{0}", se.Address);
Console.WriteLine("Physical address: \t{0}", se.ListenUri);
Console.WriteLine("Binding: \t{0}", se.Binding.Name);
Console.WriteLine();
}
Console.Read();
}

输出结果如图1所示:



图1

设定物理地址

前面我们输出的结果逻辑地址和物理地址是相同的,我们可以通过代码或者配置文件来设定终结点的物理地址。
WSHttpBinding wsbinding = new WSHttpBinding();
calculatorServiceHost.AddServiceEndpoint(
typeof(ICalculator),
wsbinding,
"urn:calcservice",  // 逻辑地址
new Uri("http://localhost:8887/CalculatorService")  // 物理地址
);

又或者通过配置文件来设置ListenUri,如下代码所示:
<endpoint address="urn:calcservice"
binding ="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator"
listenUri="http://localhost:8887/CalculatorService"
bindingConfiguration="securityBinding">
</endpoint>

这里我们只需要注意的是在指定物理地址时,仍然可以使用相对地址,这一点与设置逻辑地址时是一样的。

工作原理

现在思考一个核心的问题,当我们定义了终结点后,在WSDL中包含的是每个终结点的逻辑地址,而非物理地址,如下代码片段:
<wsdl:service name="CalculatorService">
<wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
<soap12:address location="urn:calcservice" />
<wsa10:EndpointReference>
<wsa10:Address>urn:calcservice</wsa10:Address>
</wsa10:EndpointReference>
</wsdl:port>
</wsdl:service>

如果物理地址与逻辑地址相同的,就不会有任何问题,但是客户端如何与一个配置了不同物理地址的服务进行交互?因为客户端并不关心服务端是否配置了不同的物理地址,它只知道每个终结点有一个唯一的终结点地址,只需要跟该地址交互即可,该地址也将作为SOAP消息放在“To”标头中。
这时我们需要有一个特殊机制,来通知客户端要使用的物理地址,然后客户端通过物理地址传送外发消息,就如同它是路由器或者某种类型的中介一样,可以通过ClientViaBehavior来实现这一点,如下代码所示:
<system.serviceModel>
<client>
<endpoint address="urn:calcservice"
binding="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator"
name="defualtEndpoint"
behaviorConfiguration="calculatorEndpointBehavior"
bindingConfiguration="securityBinding">
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="calculatorEndpointBehavior">
<clientVia viaUri="http://localhost:8887/CalculatorService" />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>

此时客户端将通过与服务终结点相同的物理地址(http://localhost:8887/CalculatorService)向外传送消息而不是通过“urn:calcservice”,但请注意,在SOAP消息“To”标头中包含的仍然是逻辑地址,如图2所示:



图2
看到上面这幅图,可能大家还有一个疑问,逻辑地址起什么作用呢?别忘了我们前面讲到的消息筛选,当消息到达时,ChannelDispatcher 查询每个相关的 EndpointDispatcher 对象以确定终结点是否可以接受消息,以及将该消息传递到可以接受消息的终结点。当消息的目标地址(To标头中的地址)与 AddressFilter 属性相匹配并且消息操作与 ContractFilter 属性相匹配时,EndpointDispatcher 对象负责处理来自 ChannelDispatcher 的消息。

物理地址模式

了解了物理地址和逻辑地址之间的关系,我们再看一下在设置监听地址时的两种模式,通过ListenUriMode枚举来指定,它定义了两个枚举值:
Explicit:完全原样使用 ListenUri,默认值。
Unique:指定传输是否应使用特定传输机制,以确保 ListenUri 是唯一的
根据传输所采用的协议不同,WCF会采用不同的策略来保证ListenUri唯一,具体的策略如下所示:
1.非TCP传输,在ListenUri的末尾附加一个GUID。
2.对于独占模式下的 TCP(PortSharingEnabled 为 false),绑定到一个唯一可用端口号。
3.对于端口共享模式下的 TCP(PortSharingEnabled 为 true),在ListenUri的末尾附加一个GUID。

TcpTrace消息截获

前面讲了这么多物理地址和逻辑地址,它们最重要的使用地方就是做路由。我们常用tcpTrace来做SOAP消息跟踪,它正是利用这一点技术,在客户端配置ClientViaBehavior,指向tcpTrace的侦听地址,然后tcpTrace在对消息做记录后再转发到服务端,如在服务端的配置如下,它的物理地址和逻辑是相同的:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
behaviorConfiguration="calculatorBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8887/Calculator"/>
</baseAddresses>
</host>
<endpoint address="http://localhost:8887/CalculatorService"
binding ="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator">
</endpoint>
</service>

客户端的配置,这里“http://localhost:8887/CalculatorService”是真正的服务地址(逻辑地址),我们通过ClientViaBehavior告诉客户端物理地址是“http://localhost:8080/CalculatorService”,事实上处于该物理地址的服务并不存在,该地址是tcpTrace的监听地址:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8887/CalculatorService"
binding="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator"
behaviorConfiguration="calculatorEndpointBehavior">
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="calculatorEndpointBehavior">
<clientVia viaUri="http://localhost:8080/CalculatorService" />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

tcpTrace的配置如图3所示:



图3
这里tcpTrace监听的端口号就是我们在客户端配置的物理地址端口号,而分发地址才是服务的真正地址,最终可以看到截获的消息,如图4所示:



图4
如果不在客户端配置ClientViaBehavior,利用物理地址和逻辑地址的知识,我们还可以有另外一种方式使用tcpTrace。前面我说过,逻辑地址是包含在WSDL中,所以对于客户端来说知道的是逻辑地址,它会向该地址发送消息,这样我们可以配置终结点的逻辑地址为tcpTrace侦听的地址,而为服务端指定另外一个物理地址,并配置tcpTrace向该物理地址转发消息,如服务端的配置如下:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
behaviorConfiguration="calculatorBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Calculator"/>
</baseAddresses>
</host>
<endpoint address="http://localhost:8887/CalculatorService"
binding ="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator"
listenUri="http://localhost:8080/CalculatorService">
</endpoint>
</service>

而客户端则不用再配置ClientViaBehavior,如下代码所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8887/CalculatorService"
binding="wsHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator">
</endpoint>
</client>
</system.serviceModel>
</configuration>

现在“http://localhost:8887/CalculatorService”是逻辑地址,配置tcpTrace监听该地址,并向服务的物理地址“http://localhost:8080/CalculatorService”转发消息,如图5所示:



图5
可以看到,利用物理地址和逻辑地址的知识,可以轻松的实现路由,当然tcpTrace只是路由中非常简单的一种使用,后面我们还会讲到更加复杂的应用。

结束语

本文详细介绍了WCF中的物理地址和逻辑地址,它的相关原理以及如何使用tcpTrace来实现SOAP消息的跟踪。关于WCF寻址相关文章:
WCF专题系列(4):深入WCF寻址Part 4—自定义消息筛选器
WCF专题系列(3):深入WCF寻址Part 3—消息过滤引擎
WCF专题系列(2):深入WCF寻址Part 2—自定义寻址报头
WCF专题系列(1):深入WCF寻址Part 1—Web服务寻址规范
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息