WCF 4新功能介紹(1)

by Vivid 24. 八月 2011 01:00

.NET Magazine國際中文電子雜誌

作 者:許薰尹

審 稿:張智凱

文章編號:N110811502

出刊日期:2011/08/24

 

Windows Communication Foundation (WCF) 3.5版的程式,可以毫無問題直接升級到.NET Framework 4,不會有不相容的問題。在.NET Framework 4中的WCF 4新增以下新功能,讓你可以更容易設計出服務導向類型的程式碼:

  • 簡易組態設定。
  • 服務探索。
  • 服務繞送。
  • WCF Web HTTP 服務輔助說明頁面。

此外,WCF 4與WF 4也做了更緊密的整合。

簡易組態設定

WCF在設計時,通常會利用組態檔案來定義服務的端點資訊,但這也讓初學者不易學習。在WCF 4中你可以設計不需要組態的服務,改用預設的組態設定來運行。雖然WCF 4提供了許多預設的組態設定,在必要時,你可以改寫他們,以便更容易進行控管。預設若裝載程式接聽的URI基底位址以「http://」起始,便會使用「basicHttpBinding」;若是以net.tcp開始,則使用netTcpBinding參考以下所示:

  • http:basicHttpBinding
  • net.pipe:netNamedPipeBinding
  • net.msmq:netMsmqBinding
  • net.tcp:netTcpBinding

假設使用Visual Studio 2010建立一個「WCF Service Application」專案,將IService1服務定義如下,其中包含一個SayHi方法,需要傳入一個字串參數,並回傳一個字串:

namespace WCF4Demo {  
    [ ServiceContract]
    public interface IService1 {
        [OperationContract]
        string SayHi ( string name );
    }
}

 

在Service1類別實作介面,SayHi方法會回傳一個字串:

namespace WCF4Demo {
   
    public class Service1 :IService1 {
        public string SayHi ( string name ) {
            return "Hi," + name;
        }
    }
}

 

接著在專案之中加入一個Service1.svc檔案,將此服務裝載在Web伺服器:

<%@ ServiceHost Language = "C#" Debug = "true" Service = "WCF4Demo.Service1" CodeBehind = "Service1.svc.cs" %>

基本上Web.config組態檔案並不需要做特殊設定,這個WCF服務便可以執行,參考以下圖1,當執行這個網站便可以看到WCF服務測試頁面。

clip_image002

圖 1:WCF服務測試頁面。

WCF服務會使用預設的組態設定執行,在預設情況下,服務裝載在Web伺服器時,會使用http協定透過basicHttpBinding來進行溝通。預設也會停用Metadata發行,因此您無法利用Visual Studio加入服務參考的功能來建立叫用服務所需的用戶端代理類別。

預設繫結(Binding)與行為(Behavior)

在WCF 4之中,只要不設定組態檔,或Behavior的名稱,就可以建立讓所有端點共用的Binding與Behavior。例如以下範例,為了要開放Metadata,在組態檔案之中,加入了serviceBehaviors區段,將serviceMetadata項目的 httpGetEnabled屬性設定為true。因為service behavior的名稱為空白,它會自動套用到所有沒有名稱的服務:

<?xml version = "1.0"? >
<configuration>
    <system.web>
        <compilation debug = "true" targetFramework = "4.0" />
    </system.web>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name = "" >
                    <serviceMetadata httpGetEnabled = "true" />
                    <serviceDebug includeExceptionDetailInFaults = "false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled = "true" />
    </system.serviceModel>
</configuration>

 

用戶端應用程式可以直接加入服務參考,取得服務的Metadata,並產生代理程式,參考圖2所示:

clip_image004

圖 2:產生代理程式。

我們建立一個Console應用程式當用戶端,建立代理物件,然後叫用服務的SayHi方法,並將回傳的字串印出在主控台:

namespace WCF4ConsoleClient {
    class Program {
        static void Main (string[] args) {
            ServiceReference1.Service1Client svc = new ServiceReference1.Service1Client ();
            Console.WriteLine ( svc.SayHi ("Mary") );
        }
    }
}

 

若想要更改服務預設使用的Binding,則可以在組態檔案中加入一個protocolMapping區段來定義,例如以下組態設定改變http scheme的預設Binding為「ws2007HttpBinding」,因為使用http的話,預設會使用BasicHttpBinding:

<system.serviceModel>
      <protocolMapping>
        <add scheme = "http" binding = "ws2007HttpBinding" />
      </protocolMapping>

</system.serviceModel>

 

不需svc 檔案

在WCF 4中若服務是裝載在Web伺服器上,你可以不需要使用svc檔案,只要在組態檔案加上serviceActivations項目:

<serviceHostingEnvironment multipleSiteBindingsEnabled = "true" >
        <serviceActivations>
          <add relativeAddress = "Service1.svc" service = "WCF4Demo.Service1" />
        </serviceActivations>
      </serviceHostingEnvironment>

 

當網站執行時,您還是可以利用以下URI「http://主機名稱/svc檔名稱」存取到服務,例如圖3所示。

clip_image006

圖 3:存取服務。

使用Console Host

再來看一個簡易組態的例子,若您需要自行撰寫裝載服務的Host程式,您只需要建立ServiceHost物件,叫用Open方法接聽服務即可,不需要設定任何組態檔。

using System.ServiceModel;
namespace ConfiglessHost {
    class Program {
        static void Main ( string[] args ) {
            ServiceHost host = new ServiceHost ( typeof (WCF4Demo.Service1) ,
new Uri ("http://localhost:2924/Service1") );
            host.Open ();
            Console.WriteLine ( "WCF Service running..." );
            Console.ReadLine ();
            host.Close ();
        }
    }
}

 

預設端點

在WCF 3.5版中,當建立一個服務,您需要在裝載程式中利用程式或者是組態檔案描述服務的端點資訊,才能讓用戶端程式存取,每建立一個服務就要做一次設定,這是一件很煩瑣的事。WCF 4預設提供了自動新增端點的功能可以讓你建立預設端點 (Default Endpoint),而不用在組態檔案或程式中建立,或者也可以叫用ServiceHost 的AddDefaultEndpoints方法客製化處理。

WCF 4裝載程式會使用以下資訊自動為服務建立端點:

  1. 位址(Address):服務的基礎位址。
  2. 繫結(Binding):根據預設URI scheme的對應來決定要使用的Binding類型。若是「http」URI scheme則預設使用basicHttpBinding。若是「net.tcp」 URI scheme則預設會自動使用NetTcpBinding。
  3. 合約(Contract):根據定義服務合約的介面與實作的類別來決定,若服務實作了兩個合約,則就會產生兩個端點。

例如以下範例程式,建立ServiceHost,接聽兩個埠號:一為http URI scheme;一為net.tcp URI scheme, ServiceHost開始接聽後,利用一個foreach迴圈列印出服務所有端點的Address、Binding與合約資訊:

using System.ServiceModel;
using System.ServiceModel.Description;
namespace ConfiglessHost {
    class Program {
        static void Main (string[] args) {
            ServiceHost host = new ServiceHost ( typeof (WCF4Demo.Service1) ,
              new Uri ( "http://localhost:2924/Service1") ,
             new Uri ("net.tcp://localhost:8081/Service1"));
            //host.AddDefaultEndpoints ();
            host.Open ();
            foreach (ServiceEndpoint se in host.Description.Endpoints)
                Console.WriteLine (se.Address +"\t"+ se.Binding.Name +"\t" +se.Contract.Name);
        

            Console.WriteLine ("WCF Service running...");
            Console.ReadLine ();
            host.Close ();
        }
    }
}

印出的結果如下,使用「http」URI scheme的端點預設會使用basicHttpBinding;而「net.tcp」 URI scheme則預設會使用NetTcpBinding,參考圖4所示。

clip_image008

圖 4:使用預設端點。

標準端點(Standard Endpoint)

WCF 4 內建許多標準的端點,這些端點都具備基本預設的組態設定,並簡化了端點的定義動作,只要簡單地使用屬性來描述端點的位址、繫結與合約,可以滿足大部分開發的需求。例如mexEndpoint定義一個合約固定是IMetadataExchange的標準端點,WCF提供的標準端點如下:

  • announcementEndpoint
  • discoveryEndpoint
  • dynamicEndpoint
  • mexEndpoint
  • udpAnnouncementEndpoint
  • udpDiscoveryEndpoint
  • webHttpEndpoint
  • webScriptEndpoint
  • workflowControlEndpoint

若要使用標準的端點組態,只要在組態檔案中加一個endpoint項目,設定其kind Attribute,例如在WCF 3.5版,要定義一個Http端點開放Metadata,您的服務可以使用以下組態檔案,定義一個mex端點:

<system.serviceModel>
    <services>
      <service name = "WCF4DemoService.Service1" >
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8888/Service1/"   />
          </baseAddresses>
        </host>
        <endpoint address = ""  binding = "basicHttpBinding" contract = "WCF4DemoService.IService1" >
         </endpoint>
        <endpoint address = "mex" binding = "mexHttpBinding" contract = "IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
           <serviceMetadata  httpGetEnabled = "true" />
          <serviceDebug includeExceptionDetailInFaults = "False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

 

在WCF 4版,你可以使用kind Attribute來定義標準端點(Standard Endpoint),不需要明確地定義這個端點使用的位址、Binding與合約,現在只要把mex端點那行組態設定更改如下即可:

<endpoint address = "mex" kind = "mexEndpoint" />

服務探索

用戶端程式若將服務所在的主機名稱或IP位置資訊寫死在程式或是組態檔案,當服務所在的主機名稱或IP位置變更時,要變更用戶端的程式或組態檔來找到新的服務位置是一件很麻煩的事。

WCF 4提供Discovery API,以便動態發行、探索服務,用戶端不必明確的知道服務真正的位址。WCF遵循WS-Discovery協定設計,在System.ServiceModel.Discovery命名空間下實作了WS-Discovery 協定,並新增一個ServiceDiscoveryBehavior類別來更改服務的行為,以便開放服務探索功能。您可以利用UdpAnnouncementEndpoint類別來監聽是否有探索的請求送達。

目前WCF 4提供兩種探索機制:

  • 即時探索(ad hoc discovery):服務在網路中利用UDP廣播自己的位置,或接聽搜尋訊息,此作法會造成較多網路流量但不會成為單一故障點(single point of failure)。只限定在目前的子網路(subnet)中使用,不適合在網際網路中使用。用戶端程式要搜尋網路找尋服務,或接聽服務送出的公告(Announcement)。
  • Manage Discovery:需要有一台集中的伺服器(Server),或Discovery Proxy集中管理服務的清單,接聽公告(Announcement)或probe/resolve類型的搜尋訊息。當服務啟動時,當作服務和用戶端的中介者,通知Discovery Proxy服務所在位址。實作上較為複雜,但網路流量較小,較適合大型企業,可以使用除UDP之外的其它類型的協定(UDP不支援),如TCP、HTTP,適合在網際網路中使用。但Discovery Proxy可能會成為網路的單一故障點。

即時探索(ad hoc discovery)—非同步探索

你可以為服務設計即時探索(ad hoc discovery)功能,當服務初始化時,將使用UDP 廣播一個「Hello」公告,表明服務的存在。正在監聽中的用戶端程式若收到服務送出的「Hello」公告訊息,便可知道服務所在以及服務端點資訊,後續便可利用這些資訊和服務互動。當服務停止執行,也會利用UDP送出一個「Bye」訊息,通知用戶端,參考圖5所示。

clip_image010

圖 5:即時探索。

用戶端程式並不一定會接聽服務的公告(Announcement),因此用戶端程式也可以根據一些篩選條件,如服務合約,使用UDP送出探測訊息(Probe)主動搜尋網路中的服務,正在監聽這些訊息的服務若收到探測訊息,可以送出ProbeMatch訊息來回應。回應的訊息中會包含服務開放的端點資訊,以便讓用戶端程式叫用。用戶端程式也可以依據位址(Address)送出解析(Resolve)訊息來找尋服務,服務會送出ResolveMatch訊息回應,參考圖6所示。

clip_image012

圖 6:探測訊息(Probe)與解析訊息(Resolve)。

服務若要啟用即時探索功能,以便在服務啟動與停止執行時傳送公告(Announcement),你需要設定Service Behavior,您可以在組態檔案之中或程式碼加以設定,例如以下利用組態檔,加入以下serviceDiscovery設定,以便啟用服務探索功能:

<serviceBehaviors>
        <behavior name = "DiscoveryBehavior" >
          <serviceDiscovery />
        </behavior>
</serviceBehaviors>

你可以使用程式碼或在服務的組態利用behaviorConfiguration套用行為,開放服務探索的功能。若要服務接收UDP探索訊息(如Probe或Resolve訊息),你可以新增一個UDP Discovery Endpoint端點到服務之中。你可以手動指定端點,或者利用WCF事先定義的標準端點來處理探索訊息。以下組態在服務中新增一個kind Attribute以利用標準的udpDiscoveryEndpoint端點,不必明確地指定正確的位址、Binding與端點使用的合約,讓服務套用serviceDiscovery行為:

<service name = "BankServiceLibrary.BankService" behaviorConfiguration = "DiscoveryBehavior" >
        <endpoint address = "" binding = "wsHttpBinding" contract = "BankServiceLibrary.IBank" >
          <identity>
            <dns value = "localhost" />
          </identity>
        </endpoint>
        <endpoint address = "mex" binding = "mexHttpBinding" contract = "IMetadataExchange" />
        <endpoint  name= " udpDisEP" kind = "udpDiscoveryEndpoint" />
</service>

 

用戶端會利用WS-Discovery探索訊息來搜尋網路中可用的服務。Kind Attribute則指明要使用UDP方式來接聽探索訊息。

設計用戶端程式時,需要加入System.ServiceModel.Discovery組件的參考,如圖7所示。

clip_image014

圖 7:加入System.ServiceModel.Discovery組件的參考。

接著用戶端程式可以使用即時探索功能,來搜尋網路中的服務,例如圖8是文中範例進行即時探索後,將找到的WCF服務名稱顯示在清單方塊上:

clip_image016

圖 8:用戶端應用程式

用戶端程式可以利用System.ServiceModel.Discovery命名空間下的DiscoveryClient類別或DynamicEndpoint類別來探索服務,例如以下程式碼是使用DynamicEndpoint類別來進行即時探索(ad-hoc Discovery):

DynamicEndpoint dynamicEndpoint = new DynamicEndpoint (
            ContractDescription.GetContract ( typeof (ServiceReference1.IService1) ) ,
                                                 new WSHttpBinding () );
dynamic c = new ServiceReference1.Service1Client ( dynamicEndpoint );
MessageBox.Show ( c.SayHi("Mary") );

 

DynamicEndpoint類別會送出「探測(Probe)」訊息,並根據事先設定好的篩選條件來找尋服務。以這個例子來說,DynamicEndpoint類別會利用ServiceReference1.IService1合約和WSHttpBinding當作篩選條件找尋服務,找到服務之後,服務會送出ProbeMatch訊息,接著DynamicEndpoint接收服務回應的端點資訊,選擇其中一個端點來存取服務。

使用DynamicEndpoint類別時,如果想要更進一步設定篩選條件,您可以利用DynamicEndpoint類別的FindCriteria屬性來設定「Scope Filter」或「Contract Filter」指定更精確的篩選條件。FindCriteria的ScopeMatchBy屬性可以設定為:

  • FindCriteria.ScopeMatchByExact:找尋範圍(Scope)中,大小寫需完全符合篩選條件。
  • FindCriteria.ScopeMatchByLdap:使用Lightweight Directory Access Protocol (LDAP)。
  • FindCriteria.ScopeMatchByNone:找尋沒有定義Scope的端點。
  • FindCriteria.ScopeMatchByPrefix:前置字串符合。
  • FindCriteria.ScopeMatchByUuid:使用UUID比對。

Service Discovery可能會找到多個服務的端點,若想要更進一步控管想使用的端點,可以改用DiscoveryClient類別。DiscoveryClient類別支援同步以及非同步的探索功能,若要使用同步探索,可以叫用它的Find方法;若要使用非同步探索,則可以使用FindAsync方法,然後註冊FindProgressChanged或FindCompleted事件處理常式來做因應的處理。每次探索到服務時,會觸發FindProgressChanged事件,探索完成將觸發FindCompleted事件。以下程式範例利用非同步方式叫用DiscoveryClient類別的FindAsync方法探索服務,並在此方法中利用FindCriteria類別限定要搜尋有實作IService1介面的端點。若探索到服務,則在dc_FindProgressChanged事件處理常式中,將服務位址加入清單方塊;探索完成後,則叫用清單方塊中第一個服務:

private DiscoveryClient dc;
        private void button2_Click ( object sender , RoutedEventArgs e ) {
            this.dc = new DiscoveryClient ( new UdpDiscoveryEndpoint () );
            this.dc.FindProgressChanged += new EventHandler<FindProgressChangedEventArgs> ( dc_FindProgressChanged );
            this.dc.FindCompleted += new EventHandler<FindCompletedEventArgs> ( dc_FindCompleted );
            this.dc.FindAsync ( new FindCriteria (typeof (ServiceReference1.IService1) ) );
        }
        void dc_FindCompleted ( object sender , FindCompletedEventArgs e ) {
            if ( e.Cancelled ) {
                MessageBox.Show ( "取消" );
            } else if ( e.Error != null ) {
                this.dc.Close ();
                MessageBox.Show ( e.Error.Message );
            } else {
                if ( this.dc.InnerChannel.State == CommunicationState.Opened ) {
                    this.dc.Close ();
                }
            }
            this.dc = null;
            label1.Content= "finish";
            if ( listBox1.Items.Count != 0 ) {
                EndpointAddress addr = new EndpointAddress ( new Uri (listBox1.Items[0].ToString ()) );
                dynamic c = new ServiceReference1.Service1Client ( new WSHttpBinding () , addr );
                MessageBox.Show ( c.SayHi ("Mary") );
            }
        }
        void dc_FindProgressChanged ( object sender , FindProgressChangedEventArgs e ) {
            listBox1.Items.Add ( e.EndpointDiscoveryMetadata.Address );
        }

使用Console裝載服務

若要裝載實作了即時探索功能的裝載程式,您可以在裝載程式中建立ServiceDiscoveryBehavior類別,啟用服務探索功能,然後新增一個UdpDiscoveryEndpoint端點,參考以下範例程式使用Console來裝載服務:

Uri baseAddress = new Uri ("http://localhost:2924/");
            Type instanceType = typeof ( WCF4Demo.Service1 );

            ServiceHost host = new ServiceHost ( instanceType , baseAddress );
            using ( host ) {
                Type contractType = typeof ( WCF4Demo.IService1 );
                string relativeAddress = "Service1";
                host.AddServiceEndpoint (c ontractType ,
                   new WSHttpBinding () , relativeAddress );

                ServiceMetadataBehavior md = new ServiceMetadataBehavior ();
                md.HttpGetEnabled = true;
                host.Description.Behaviors.Add ( md );

                ServiceDiscoveryBehavior sdb = new ServiceDiscoveryBehavior ();
                host.Description.Behaviors.Add ( sdb );
                host.AddServiceEndpoint ( new UdpDiscoveryEndpoint () );
                host.Open ();
                Console.WriteLine ("Service " + "running. Press <ENTER> to quit." );
                Console.ReadLine ();
                host.Close ();
            }

即時探索(ad hoc discovery)—同步探索

若要採用同步方式進行服務探索,則裝載服務的程式如下,利用AnnouncementEndpoints.Add方法,加入服務行為(Service behavior),指明使用UdpAnnouncementEndpoint端點來進行公告:

using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Discovery;
using System.ServiceModel.Routing;

namespace WF4ConHost {
    class Program {
        static void Main ( string[] args ) {
            Uri baseAddress = new Uri ( "http://localhost:2924/Service1" );
            Type instanceType = typeof ( WCF4Demo.Service1 );
            ServiceHost host = new ServiceHost ( instanceType , baseAddress );
            host.AddServiceEndpoint ( typeof (WCF4Demo.IService1) , new WSHttpBinding () , "sv1" );
            host.AddServiceEndpoint ( typeof (WCF4Demo.IService1) , new WS2007HttpBinding () , "sv2" );
            host.Description.Behaviors.Add ( new ServiceMetadataBehavior () { HttpGetEnabled = true } );
            ServiceDiscoveryBehavior discoBehav = new ServiceDiscoveryBehavior ();
            host.Description.Behaviors.Add (discoBehav);
            host.AddServiceEndpoint ( new UdpDiscoveryEndpoint () );
            discoBehav.AnnouncementEndpoints.Add ( new UdpAnnouncementEndpoint () );
            host.Open ();
            Console.WriteLine ("WCF Service " + "running. Press <ENTER> to quit." );
            Console.ReadLine ();
            host.Close ();
        }  }  }

 

用戶端程式可以透過DiscoveryClient類別來進行探索,以下範例程式利用DiscoveryClient類別的Find方法搜尋網路中的IService1服務,並叫用第一個被搜尋到的服務之SayHi方法。

DiscoveryClient dc = new DiscoveryClient( new UdpDiscoveryEndpoint () );
            FindResponse resp = dc.Find (new FindCriteria ( typeof (IService1 ) ) );
            for ( int i = 0 ; i < resp.Endpoints.Count ; i++ ) {
                listBox1.Items.Add ( resp.Endpoints[i].Address.ToString () );
            }
// 第一個端點走WSHttpBinding
EndpointAddress addr = resp.Endpoints[0].Address;
Service1Client svc = new Service1Client ( new WSHttpBinding () , addr );
MessageBox.Show ( svc.SayHi ("Mary") );

 

使用Metadata Extensions擴充WS-Discovery功能

您可以擴充WS-Discovery功能,額外增加一些客製化的資訊到探索訊息之中。例如在裝載WCF服務的程式中,利用以下程式碼新增一個EndpointDiscoveryBehavior,利用EndpointDiscoveryBehavior的Extensions屬性,傳入一個XElement 項目記錄裝載服務所在的伺服器名稱「wcfserver」:

EndpointDiscoveryBehavior epb = new EndpointDiscoveryBehavior ();
epb.Extensions.Add( new XElement ( "root" ,  new XElement ( "Name" , "wcfserver") ) );
ServiceEndpoint ep = host.Description.Endpoints.Find ( typeof (WCF4Demo.IService1) );
ep.Behaviors.Add (epb);

 

而在用戶端搜尋到服務時,便能利用Metadata Extensions取出其值,參考程式碼如下:

void dc_FindProgressChanged ( object sender , FindProgressChangedEventArgs e ) {
   XElement srvNameEle = e.EndpointDiscoveryMetadata.Extensions.Elements ("Name").FirstOrDefault ();
            string srvName = "" ;
            if ( srvNameEle != null ) srvName = srvNameEle.Value;
            listBox1.Items.Add ( e.EndpointDiscoveryMetadata.Address + "\t" + srvName);
}

 

參考圖9是以上使用Metadata Extensions擴充WS-Discovery功能範例執行的結果。

clip_image018

圖 9:使用Metadata Extensions擴充WS-Discovery功能。

探索公告(Discovery Announcement)

用戶端也可以接聽探索公告(Discovery Announcement)來得知服務是否上線(Online)或離線(Offline),來得知服務的存在與否。這樣的好處是網路封包流量會變得較小。WCF Discovery利用AnnouncementEndpoint與UdpAnnouncementEndpoint類別讓用戶端和服務能夠互相通知。

若要達到這樣的目地,則服務端需要新增一個UdpAnnouncementEndpoint端點:

ServiceDiscoveryBehavior sdb = new ServiceDiscoveryBehavior ();
//AnnouncementEndpoints
sdb.AnnouncementEndpoints.Add ( new UdpAnnouncementEndpoint () );
host.Description.Behaviors.Add ( sdb );

 

當你將UdpAnnouncementEndpoint加入ServiceDiscoveryBehavior,服務會傳送上線與離線訊息到用戶端。

用戶端需要裝載AnnouncementService,然後註冊OnlineAnnouncementReceived與OfflineAnnouncementReceived事件,例如以下程式所示:

AnnouncementService ann = new AnnouncementService ();
ServiceHost host;
private void Window_Loaded ( object sender , RoutedEventArgs e ) {
            ann.OnlineAnnouncementReceived += new EventHandler<AnnouncementEventArgs> ( announcementService_OnlineAnnouncementReceived );
            ann.OfflineAnnouncementReceived += new EventHandler<AnnouncementEventArgs> ( announcementService_OfflineAnnouncementReceived );
             host = new ServiceHost ( ann );
            host.AddServiceEndpoint ( new UdpAnnouncementEndpoint () );
            host.Open ();
        }
private void Window_Unloaded ( object sender , RoutedEventArgs e ) {
            if ( host.State == CommunicationState.Opened ) {  host.Close ();  }
}
void announcementService_OfflineAnnouncementReceived (object sender , AnnouncementEventArgs e ) {
            MessageBox.Show ("Offline: " + e.EndpointDiscoveryMetadata.Address );
}
void announcementService_OnlineAnnouncementReceived (object sender , AnnouncementEventArgs e) {
            MessageBox.Show ( "Online: " + e.EndpointDiscoveryMetadata.Address );
        }

 

當裝載服務的程式執行,用戶端程式便會收到上線訊息。當裝載服務的程式結束執行,用戶端程式便會收到離線訊息,參考圖10所示。

clip_image020

圖 10:用戶端程式會收到服務上線、離線訊息。

服務探索--Manage Discovery

Ad-Hoc Discovery是使用UPD方式進行廣播,因此不能在網際網路之中使用,此時你可以改用Manage Discovery。Manage Discovery的探索動作不受限於某個子網路中,只要向Discovery Proxy註冊,便可透過它來做服務探索。Discovery Proxy是存在於企業內部中的一個服務,可以對外開放一個查詢的端點,供存在於其它外部網路的用戶端來取用。Discovery Proxy可以接聽內部網路中服務啟動與關閉時的公告資訊,來得知服務的訊息,將服務的資訊儲存在Discovery Proxy快取清單中,或從清單中移除。當Discovery Proxy收到用戶端送達的「Probe」或「Resolve」訊息,便可將快取清單中的服務資訊回應給用戶端。

clip_image022

圖 11:服務探索--Manage Discovery。

Discovery Proxy在實作時也可以選擇在內部網路送出UDP廣播(UDP Multicast),搜尋內部網路中的服務,並將服務的資訊儲存在快取。接著在收到用戶端送達的「Probe」或「Resolve」訊息時,送出「ProbeMatch」或「ResolveMatch」訊息回應。

clip_image024

圖 12:Discovery Proxy

當然你也可以在Discovery Proxy混用上述兩種作法。麻煩的是,WCF 4架構並未幫你實作出Discovery Proxy程式,您可以繼承System.ServiceModel.Discovery.DiscoveryProxy類別改寫它的方法來建立Discovery Proxy,這些方法都遵循非同步模型來設計。在設計時,專案的Target Framework要設定為「.NET Framework 4.0」,「.NET Framework 4.0 Client Profile」不支援這個進階的功能。

用戶端程式可以使用DiscoveryEndpoint指定Binding與位址來連結到Discovery Proxy。若要送出查詢則可以使用DiscoveryClient的Find方法,指定查詢的篩選條件送出「Proxy」訊息來查詢Discovery Proxy。或者使用DiscoveryClient的Resolve方法根據位址送出「Resolve」訊息來查詢。

 

總結

即時探索是依賴一個UDP multicast的端點進行探索。埠號與multicast address在WS-Discovery協定的文件指定。即時探索限定在相同子網路(subnet)中才能夠使用。

在WCF 4你可以在不定義任何端點的情況下,裝載你的服務並定義基礎位址。

為簡化設定,WCF允許你定義預設的行為(Default Behavior)與Binding組態。

若要將服務裝載在較可靠的環境,你可以使用IIS、WAS或IIS擴充程式AppFabric,裝載在AppFabric可以加以監控服務的活動情況,追蹤服務的運作和狀態。

用戶端程式可以送出「Probe」或「Resolve」訊息到Discovery Proxy進行探測。

Tags:

NET 開發 | 許薰尹Vivid Hsu | WCF | .NET Magazine國際中文電子雜誌

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List