[WCF-Discovery] 客戶端如何能夠“探測”到可用的服務?
當應用了ServiceDiscoveryBehavior行為的服務通過標準終結點DiscoveryEndpoint被發布出來之后(《[WCF-Discovery]服務如何能被”發現”》),客戶端就可以按照WS-Discovery中定義的方式對可用的目標方式進行探測和解析了。由于這個過程本質上就是一次普通的服務調用,具體來說是針對發布發現服務(非目標服務)的標準終結點DiscoveryEndpoint的調用,所以客戶端也需要具有這么一個匹配的終結點。
目錄:
一、DiscoveryClient
二、FindCriteria/FindResponse
三、ResolveCriteria/ResolveResponse
一、DiscoveryClient
客戶端針對可用目標服務的探測與解析都是通過DiscoveryClient對象來實現的,下面的代碼片斷給出了DiscoveryClient的定義。我們可以直接通過一個DiscoveryEndpoint對象,或者是DiscoveryEndpoint的配置名稱來創建DiscoveryClient對象。
public sealed class DiscoveryClient : ICommunicationObject, IDisposable,... { //事件 public event EventHandler<FindCompletedEventArgs> FindCompleted; public event EventHandler<ResolveCompletedEventArgs> ResolveCompleted; //構造函數 public DiscoveryClient(DiscoveryEndpoint discoveryEndpoint); public DiscoveryClient(string endpointConfigurationName); //Find public FindResponse Find(FindCriteria criteria); public void FindAsync(FindCriteria criteria); public void FindAsync(FindCriteria criteria, object userState); //Resolve public ResolveResponse Resolve(ResolveCriteria criteria); public void ResolveAsync(ResolveCriteria criteria); public void ResolveAsync(ResolveCriteria criteria, object userState); }
不論是用于可用服務探測的Find/FindAsync,還是用于目標服務解析的Resolve/ResolveAysnc,都需要指定相應的匹配條件。前者對應的匹配條件通過類型FindCriteria來表示,而后者匹配條件的類型則是ResolveCriteria。
同步方法Find/Resolve的返回類型分別為FindResponse和ResolveResponse。而對于異步調用,則可以通過注冊的FindCompleted/ResolveCompleted事件參數中獲取類型為FindResponse/ResolveResponse的返回值。這兩個事件的參數類型分別為FindCompletedEventArgs和ResolveCompletedEventArgs,這個兩個類型和它們的基類System.ComponentModel.AsyncCompletedEventArgs定義如下。
public class FindCompletedEventArgs : AsyncCompletedEventArgs { //其他成員 public FindResponse Result { get; } } public class ResolveCompletedEventArgs : AsyncCompletedEventArgs { //其他成員 public ResolveResponse Result { get; } } public class AsyncCompletedEventArgs : EventArgs { //其他成員 public bool Cancelled { get; } public Exception Error { get; } public object UserState { get; } }
二、FindCriteria/ FindResponse
代表Probe請求的Find方法接受一個FindCriteria類的輸入參數作為進行探測可用目標的匹配條件,該類型的主要的屬性成員定義如下。其中ContractTypeNames代表探測的目標服務實現的契約類型列表,而Scopes和ScopeMatchBy則分別代表了用于探測目標的的范圍和對范圍進行匹配的方式。
public class FindCriteria { //其他成員 public static readonly Uri ScopeMatchByExact; public static readonly Uri ScopeMatchByLdap; public static readonly Uri ScopeMatchByNone; public static readonly Uri ScopeMatchByPrefix; public static readonly Uri ScopeMatchByUuid; public Collection<XmlQualifiedName> ContractTypeNames { get; } public Collection<Uri> Scopes { get; } public Uri ScopeMatchBy { get; set; } }
public class EndpointDiscoveryBehavior : IEndpointBehavior { //其他成員 public Collection<Uri> Scopes { get; } }
<configuration> <system.serviceModel> <services> <service ...> <endpoint behaviorConfiguration="scopeMatch" .../> ... </service> </services> <behaviors> <endpointBehaviors> <behavior name="scopeMatch"> <endpointDiscovery> <scopes> <add scope="http://www.example.com/calculator"/> <add scope="ldap:///ou=engineering,o=examplecom,c=us"/> </scopes> </endpointDiscovery> </behavior> </endpointBehaviors> </system.serviceModel> </configuration>
FindCriteria的ScopeMatchBy屬性類型依然是Uri。WCF預選定義了5個Uri代表相應的進行范圍匹配的5種算法,它們對應著定義在FindCriteria的5個靜態只讀屬性:ScopeMatchByExact、ScopeMatchByLdap、ScopeMatchByNone、ScopeMatchByPrefix和ScopeMatchByUuid。
public class FindCriteria { //其他成員 public static readonly Uri ScopeMatchByExact; public static readonly Uri ScopeMatchByLdap; public static readonly Uri ScopeMatchByNone; public static readonly Uri ScopeMatchByPrefix; public static readonly Uri ScopeMatchByUuid; public Uri ScopeMatchBy { get; set; } }
- ScopeMatchByExact:對Uri進行精確匹配,Uri為http://schemas.microsoft.com/ws/2008/06/discovery/strcmp0;
- ScopeMatchByPrefix:將指定的Uri作為服務范圍的前綴進行匹配,Uri為http://schemas.microsoft.com/ws/2008/06/discovery/rfc;
- ScopeMatchByLdap:按使用LDAP URL的段來匹配范圍,Uri為http://schemas.microsoft.com/ws/2008/06/discovery/ldap;
- ScopeMatchByUuid:通過使用UUID字符串來完全匹配范圍,Uri為http://schemas.microsoft.com/ws/2008/06/discovery/uuid;
- ScopeMatchByNone:僅匹配那些未指定范圍的服務,Uri為http://schemas.microsoft.com/ws/2008/06/discovery/none。
如果采用ScopeMatchByExact,進行精確匹配是區分大小寫的。而基于前綴匹配的ScopeMatchByPrefix,實際上按以“/”分隔的段進行匹配。搜索 http://contoso/building1 與范圍為 http://contoso/building/floor1 的服務相匹配。請注意,該搜索與http://contoso/building100 不匹配,因為最后兩個段不匹配。ScopeMatchBy的值必須指定為上述的5種Uri之一,其他各式的Uri是無效的。如果未指定范圍匹配規則,則使用ScopeMatchByPrefix。
按照WS-Discovery定義的消息交換模式來看,客戶端針對Find/FindAsync方法調用實際上就是發送Probe請求。符合匹配條件的目標服務會回復以PM消息,該消息中會包含服務相關的元數據信息。最終這些PM消息中的內容會被提取出來,被封裝成FindResponse對象并最為Find方法的返回值(或者事件參數FindCompletedEventArgs的Result屬性)。接下來,我們將重點介紹FindResponse這個類型。
public class FindResponse { //其他成員 public DiscoveryMessageSequence GetMessageSequence(EndpointDiscoveryMetadata endpointDiscoveryMetadata); public Collection<EndpointDiscoveryMetadata> Endpoints { get; } }
public class EndpointDiscoveryMetadata { //其他成員 public EndpointAddress Address { get; set; } public Collection<XmlQualifiedName> ContractTypeNames { get; } public Collection<XElement> Extensions { get; } public Collection<Uri> ListenUris { get; } public Collection<Uri> Scopes { get; } public int Version { get; set; } }
public class DiscoveryMessageSequence : ... { //其他成員 public long InstanceId {get; } public long MessageNumber {get; } public Uri SequenceId {get; } }
上面我們介紹了用于進行可用服務探測的Find/FindAsync操作的輸入和輸出,接下倆我們按照相同的方式來分析用于進行服務解析的Resolve/ResolveAsync操作的輸入和輸出。首先來介紹一下用于封裝匹配條件的ResolveCriteria類型,下面給出了它核心的屬性定義。
public class ResolveCriteria { //其他成員 public EndpointAddress Address { get; set; } public Collection<XElement> Extensions { get; } public TimeSpan Duration { get; set; } }
而作為Resolve/ResolveAsync輸出的ResolveResponse類型定義很簡單。它具有兩個核心的只讀屬性,代表被解析后的服務終結點元數據的EndpointDiscoveryMetadata屬性和代表消息序列的MessageSequence屬性。
public class ResolveResponse { //其他成員 public EndpointDiscoveryMetadata EndpointDiscoveryMetadata { get;} public DiscoveryMessageSequence MessageSequence { get;} }