WCF专题系列(2):深入WCF寻址Part 2—自定义寻址报头
概述
在WCF专题系列(1):深入WCF寻址Part1一文中,我们对Web服务寻址规范做了一些认识,了解了终结点引用和消息信息报头两种结构,该规范在Web服务中的地位举足轻重,后续我们会经常提到该规范。在本文中,我们将继续深入WCF寻址的内容,包括元数据中的终结点地址,自定义寻址标头等相关信息。
终结点地址定义
了解了Web服务寻址规范,再回到WCF,在WCF中,终结点地址是由EndpointAddress类来表示的,它其中很重要的几个部分是:一个表示服务地址的统一资源定位符 (URI),一个表示服务的安全标识的 Identity 和一个可选的 Headers 集合,其中Headers用于标识终结点或与终结点交互的更多详细寻址信息。如图1所示:
图1
记的我在WCF专题系列(1):深入WCF寻址Part1一文提到过,每个终结点引用都可以包含一些添加额外标识信息的引用参数,即寻址标头,在 WCF 中,将这些引用参数建模为 AddressHeader 类的实例,这里的Headers属性就是这些实例的集合,可以通过AddressHeader类提供的静态方法CreateAddressHeader来创建一个AddressHeader实例,如下代码所示:
AddressHeader header = AddressHeader.CreateAddressHeader("basic", "http://www.cnblogs.com/terrylee", "Terrylee");
指定终结点地址
在WCF中提供了基址技术,这使的我们在指定终结点地址时可以酌情选用相对地址或者绝对地址,指定绝对地址的方法是在终结点定义中提供完全限定的地址,如下代码所示:
<service name="TerryLee.WCFAddressing.Service.CalculatorService" behaviorConfiguration="calculatorBehavior"> <endpoint address="http://localhost:8887/CalculatorService" binding ="basicHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> </service>
使用绝对地址固然简单,但是如果我们的服务需要公开多个终结点,而这些终结点地址又具有相同的基地址时,也许相对地址是更好的选择。在创建服务宿主对象时,提供一个基地址,如下代码所示:
using (ServiceHost calculatorServiceHost = new ServiceHost(typeof(CalculatorService), new Uri("http://localhost:8887/CalculatorService"))) { calculatorServiceHost.Opened += delegate { Console.WriteLine("Service begin to listen via the Address:{0}", calculatorServiceHost.BaseAddresses[0].ToString()); }; calculatorServiceHost.Open(); Console.Read(); }
又或者同时在配置文件中指定基地址,这样就无须在每个终结点中指定绝对地址了,如下代码所示:
<service name="TerryLee.WCFAddressing.Service.CalculatorService" behaviorConfiguration="calculatorBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:8887/Calculator"/> </baseAddresses> </host> <endpoint address="myservice1" binding ="basicHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> <endpoint address="myservice2" binding ="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> </service>
但请注意,基址技术是为我们在配置终结点时提供了方便,客户端对它是毫无所知的,客户端看到的仍然是绝对地址,在打开服务宿主时,它会匹配所有的相对地址,从而为每个终结点提供相应的绝对地址,如上面的示例,可以在WSDL中看到:
<wsdl:service name="CalculatorService"> <wsdl:port name="BasicHttpBinding_ICalculator" binding="tns:BasicHttpBinding_ICalculator"> <soap:address location="http://localhost:8887/Calculator/myservice1" /> </wsdl:port> <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator"> <soap12:address location="http://localhost:8887/Calculator/myservice2" /> <wsa10:EndpointReference> <wsa10:Address>http://localhost:8887/Calculator/myservice2</wsa10:Address> <Identity xmlns="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity"> <Upn>TerryLee-PC\TerryLee</Upn> </Identity> </wsa10:EndpointReference> </wsdl:port> </wsdl:service>
如果在指定了基地址的情况下,有以下几种情况:指定相对地址为空,终结点地址与基地址相同;指定相对地址不为空,追加相对地址到基地址上;指定一个绝对地址,基地址不起作用,终结点地址仍然为指定的绝对地址;指定一个绝对地址和一个与基地址不同的绑定,基地址不起作用。现在有这样一段配置信息:
<service name="TerryLee.WCFAddressing.Service.CalculatorService" behaviorConfiguration="calculatorBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:8887/Calculator"/> </baseAddresses> </host> <endpoint address="" binding ="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> <endpoint address="myservice2" binding ="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> <endpoint address="http://localhost:8886/CalculatorService" binding ="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> <endpoint address="net.tcp://localhost:8885/Calculator" binding ="netTcpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator"> </endpoint> </service>
可以在ServiceHost启动后,输出所有的终结点地址和绑定信息,如下代码:
ServiceDescription desc = calculatorServiceHost.Description; foreach (ServiceEndpoint endpoint in desc.Endpoints) { Console.WriteLine("Endpoint - address: {0}", endpoint.Address); Console.WriteLine(" binding: {0}", endpoint.Binding.Name); Console.WriteLine(" contract: {0}", endpoint.Contract.Name); }
输出结果如图2所示:
图2