終結點的地址的Uri屬性作為終結點地址的唯一標示。
包括客戶端終結點和服務端終結點。
一、服務端終結點:
服務端的終結點通過宿主的添加方法暴露出來,從而成為可以調用的資源。
下面是將服務綁定到宿主的代碼:
定義宿主時使用的是契約的實現類,也即服務類,添加終結點到宿主的使用的是契約接口。
1.1代碼實現
代碼實現往指定服務的宿主上添加終結點:
1.2配置實現
下面通過配置實現:
代碼實現對應的配置如下:
1.3svc文件的配置
下面也給出svc文件中的配置:
由於svc文件被部署到了IIS上,所以對應的有端口,本身svc是一個文件,對應的也有路徑,所以配置不用使用address字段
1.4獲取宿主上的終結點
可以向一個宿主身上添加多個服務終結點,所以一個服務可以有多個終結點。每一個服務對應着一個宿主。當然可以獲取所有的終結點。
宿主有個關於服務的描述屬性,該屬性包括了宿主的承載的所有服務終結點
1.5使用基地址+相對地址類添加契約終結點
當終結點比較多時,並且前面的部分相同時,可以通過基地址+相對地址類來添加終結點到宿主上面。
宿主這時也會根據使用的Binding類型的不同來區分請求的終結點。注意上面的一個是NetTcpBinding,一個是BasicHttpBinding。這就要求同一種綁定類型的基地址只能有一種,要不然會弄亂的。
下面是配置方式
IIS來講文件所在地點就是基地址:
1.6當一個服務同時實現了兩個契約時,需要共享相同的地址,那么必須保證其綁定是同一個。方法是new一個綁定供兩個終結點使用。
二、客戶端終結點
客戶端通過引用服務,最終生成了一個代理類:客戶端服務代理類繼承自ClientBase<TChannel>和TChannel,其中TChannel是和服務端等效的接口,不過名稱是自動生成的,我們可以使用此代理類來操作數據;也可以通過ChannelFactory<TChannel>來創建代理類來操作數據。
下面看簡單的看一下代理類的基類的部分構造方法和兩個屬性。下面的屬性有個ChannelFactory<TChannel>,其實第一種方法的代理是通過ClientBase<TChannel>的屬性創建的。
public abstract class ClientBase<TChannel>
{
protected ClientBase();
protected ClientBase(ServiceEndpoint endpoint);
protected ClientBase(string endpointConfigurationName);
protected ClientBase(Binding binding, EndpointAddress remoteAddress);
protected ClientBase(string endpointConfigurationName, EndpointAddress remoteAddress);
protected ClientBase(string endpointConfigurationName, string remoteAddress);
protected TChannel Channel { get; }
public ChannelFactory<TChannel> ChannelFactory { get; }
}
為什么客戶端能調用服務端的方法類操作數據?
由構造函數來看主要是通過使用終結點來和服務端相對應,來讓客戶端能夠找到服務端的對象。
下面給出客戶端的終結點的第一種配置:
<system.serviceModel>
<client>
<endpoint name="myEndPoint"
address="http://127.0.0.1/wcfservices/"
binding="wsHttpBinding"
contract="ServiceReference1.ICalculator">
</endpoint>
</client>
</system.serviceModel>
如果是使用上面的配置,那么就可以使用基類參數為endpointConfigurationName=myEndPoint的構造方法構造。
三、地址報頭
每個終結點都含有一個Headers屬性,客戶端來說會被添加到請求消息的報頭集合中,對於服務端來說,會提取響應的報頭信息和本地終結點的地址報頭來進行比較以選擇出於請求消息相匹配的終結點。
地址報頭的創建
AddressHeader CreateAddressHeader(string name, string ns, object value, XmlObjectSerializer serializer);
以下是服務端終結點的形狀:
下面是如何使用地址報頭的代碼:
using (ChannelFactory<CalculatorService> channelFactory = new ChannelFactory<CalculatorService>("wsHttpBinding"))
{
CalculatorService calculator = channelFactory.CreateChannel();
Uri uri = new Uri("http://127.0.0.1:3721/calculatorservice");
AddressHeader header = AddressHeader.CreateAddressHeader("Licensed User", "http://www.artech.com", "UserType");
using (OperationContextScope operationContextScope=new OperationContextScope(calculator as IContextChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(header.ToMessageHeader());
double result = calculator.Divide(1, 2);
}
}
如果AddressFilterMode為Any,報頭可以不匹配。使用如下:
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any]
public class CalculatorService:ICalculator
四、邏輯地址和物理地址
物理地址對於服務端來說是監聽地址,對於客戶端來說是真正發送的目標地址。
針對SOAP的消息交換來說,服務的邏輯地址是<To>報頭的地址。
對於服務端來說物理地址和邏輯地址分離的表現在:用於監聽地址和收到的消息TO報頭的地址不一致。
在客戶端表現邏輯地址和物理地址分離的表現:<To>的報頭地址和消息真正發送目標地址不一致。
需要中介服務參與消息路由的通信就涉及物理地址和邏輯地址的分離。
對於服務消費者來說,消息發送的邏輯地址是針對服務的最終提供者的。
<endpoint address="http://127.0.0.1:5555/service1"
binding="basicHttpBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator" />
<!--2. BasicHttpBinding + ListenUriMode.Unique-->
<!--6666加GUID-->
<endpoint address="http://127.0.0.1:6666/service2"
binding="basicHttpBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"
listenUriMode="Unique" />
<!--3. NetTcpBinding & ListenUriMode.Explicit-->
<!--7777-->
<endpoint address="net.tcp://127.0.0.1:7777/service3"
binding="netTcpBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"/>
<!--4. NetTcpBinding & ListenUriMode.Unique-->
<!--會使用未占用的端口-->
<endpoint address="net.tcp://127.0.0.1:8888/service4"
binding="netTcpBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"
listenUriMode="Unique" />
<!--5. NetTcpBinding & ListenUriMode.Unique & Port Sharing-->
<!--會使用原來的端口,后面加個GUID-->
<endpoint address="net.tcp://127.0.0.1:9999/service5"
binding="netTcpBinding"
bindingConfiguration="PortSharingBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"
listenUriMode="Unique" />
上面的配置主要說明了監聽地址和監聽方式決定了最終的監聽地址。
using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
{
host.Open();
int i = 0;
foreach (ChannelDispatcher channelDispatcher in host.ChannelDispatchers)
{
Console.WriteLine("{0}: {1}", ++i, channelDispatcher.Listener.Uri);
}
Console.ReadKey();
}
提供服務的主機,對應着一個或者多個分發器,每個分發器對應着一個或多個監聽器。
wcf提供了4中類型的行為:1.服務行為、2契約行為、3終結點行為、4操作行為。行為是客戶端或者服務端本地實現某個功能的一種方式,是一種單邊的行為。
2和4被定義為特性。3只能通過配置,1可以聲明和配置。1.服務行為,主要用於service behaviorConfiguration="" 。3.終結點行為主要用於終結點的endpoint endpointConfiguration=""
服務和終結點的行為配置如下:
終結點行為配置還可以如下:
<behaviors>
<endpointBehaviors>
<behavior name="aa" >
<clientVia viaUri="http://127.0.0.1:55551/service1"/>
</behavior>
</endpointBehaviors>
</behaviors>
上面的viaUri是代表的是物理地址,即消息真正發送的目的地址。
實現服務端邏輯地址和物理地址的分離的demo
客戶端配置:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<ws2007HttpBinding>
<binding name="myBinding">
<security mode="None"/>
</binding>
</ws2007HttpBinding>
</bindings>
<client>
<endpoint name="calculatorservice"
address="http://127.0.0.1:9999/calculatorservice"
binding="ws2007HttpBinding"
bindingConfiguration="myBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"/>
</client>
</system.serviceModel>
</configuration>
服務端配置:
<system.serviceModel>
<bindings>
<ws2007HttpBinding>
<binding name="myBinding">
<security mode="None"/>
</binding>
</ws2007HttpBinding>
</bindings>
<services>
<service name="Artech.WcfServices.Service.CalculatorService">
<endpoint address="http://127.0.0.1:9999/calculatorservice"
binding="ws2007HttpBinding"
bindingConfiguration="myBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"
listenUri="http://127.0.0.1:8888/CalculatorService"
listenUriMode="Explicit"/>
</service>
</services>
</system.serviceModel>
路由轉發設置:監聽9999,目的8888.To包含的是9999.
接下來是客戶端邏輯地址和物理地址的分離的實例:
服務端
<system.serviceModel>
<bindings>
<ws2007HttpBinding>
<binding name="myBinding">
<security mode="None"/>
</binding>
</ws2007HttpBinding>
</bindings>
<services>
<service name="Artech.WcfServices.Service.CalculatorService">
<endpoint address="http://127.0.0.1:9999/calculatorservice"
binding="ws2007HttpBinding"
bindingConfiguration="myBinding"
contract="Artech.WcfServices.Service.Interface.ICalculator"/>
</service>
</services>
</system.serviceModel>
客戶端地址
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="clientVia">
<clientVia viaUri="http://127.0.0.1:8888/calculatorservice"/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<ws2007HttpBinding>
<binding name="myBinding">
<security mode="None"/>
</binding>
</ws2007HttpBinding>
</bindings>
<client>
<endpoint name="calculatorservice"
address="http://127.0.0.1:9999/calculatorservice"
binding="ws2007HttpBinding"
bindingConfiguration="myBinding"
behaviorConfiguration="clientVia"
contract="Artech.WcfServices.Service.Interface.ICalculator"/>
</client>
</system.serviceModel>
路由轉發從8888轉到9999,雙方的Address必須相同,為了讓<To>內的地址相同。可以知道發送到哪里。
信道分發器進行請求監聽和消息接受,終結點分發器最終完成對消息的處理。
信道分發器相當於保安,當有人找公司里面的人時,保安會通知具體的公司人去處理事情。