天天看點

《WCF技術内幕》翻譯17:第1部分_第4章_WCF101:WCF快速入門

<a></a>

<a>WCF快速入門</a>

// File: HelloWCFApp.cs 

[ServiceContract] 

public interface IHelloWCF { 

[OperationContract] 

void Say(String input); 

}

定義偵聽請求消息的位址需要使用System.Uri類型,定義如何與其它消息參與者交換消息需要我們使用System.ServiceModel.Channels.Binding類型。或者這些類型的繼承類型。下面的代碼說明了如何在我們的應用裡使用

Uri和Binding類型。

// File: HelloWCFApp.csstatic void Main(){ // define where to listen for messages定義偵聽消息的位址 Uri address = new Uri("http://localhost:8000/IHelloWCF");    // define how to exchange messages定義如何交換消息 BasicHttpBinding binding = new BasicHttpBinding();}

接下來我們要使用位址(address)、綁定(binding)和契約(contract)來建構一個終結點(endpoint)并在此終結點上

偵聽發送進來的消息。通常來說,一個WCF接受程式可以建構和使用多個終結點,并且每個終結點都需要一個位址、一個綁定和一個契約。System.ServiceModel.ServiceHost類型建構和托管終結點,并管理接受應用底層結構的其他部分,比如線程

和對象的生命周期。下面代碼塊示範了如何執行個體化ServiceHost,如何添加終結點和如何開始偵聽進入的消息:

// File: HelloWCFApp.cs static void Main(){        // define where to listen for messages定義偵聽消息的位址        Uri address = new Uri("http://localhost:4000/IHelloWCF");        // define how to exchange messages定義如何交換消息        BasicHttpBinding binding = new BasicHttpBinding();        // instantiate a ServiceHost, passing the type to instantiate執行個體化ServiceHost,傳遞服務類型        // when the application receives a message        ServiceHost svc = new ServiceHost(typeof(HelloWCF));        // add an endpoint, passing the address, binding, and contract增加終結點、綁定和契約        svc.AddServiceEndpoint(typeof(IHelloWCF), binding, address);        // begin listening開始偵聽        svc.Open();        // indicate that the receiving application is ready and訓示應用準備接受消息        // keep the application from exiting immediately保持應用程式不會立即退出        Console.WriteLine("The HelloWCF receiving application is ready");        Console.ReadLine();        // close the service host關閉宿主        svc.Close(); }

也會發現,前面代碼裡調用了svc.AddServiceEndpoint 和svc.Open。AddServiceEndpoint執行個體方法設定ServiceHost

對象的屬性,這樣它将使用位址、綁定和契約參數執行的行為來偵聽消息。要着重指出的是AddServiceEndpoint方法沒有

開始循環偵聽;它僅僅是簡單地改變了ServiceHost對象的狀态(第10章會詳細讨論)。ServiceHost執行個體的Open方法建構

了消息基礎結構,并開始循環偵聽。Open方法會驗證ServiceHost對象的狀态,從它的狀态裡建構終結點,并且開始偵聽。

在目前狀态,我們編譯程式,當程式試圖建構一個終結點的時候,會出現一個異常:InvalidOperationException。原因一

目了然:在ServiceHost類型的構造函數裡,我們傳遞了HelloWCF作為參數,是以,這就表示消息基礎結構要分發消息給

我們的HelloWCF對象。是以,必然存在消息到服務成員的映射關系。最簡單的建立映射的方式就是使HelloWCF服務類實作

服務契約IHelloWCF。

using System; 

using System.ServiceModel; 

using System.ServiceModel.Channels; 

// implement the IHelloWCF service contract 

sealed class HelloWCF : IHelloWCF { 

 // indicate when a HelloWCF object is created 

 HelloWCF() { Console.WriteLine("HelloWCF object created"); } 

 static void Main(){ 

        // define where to listen for messages 

        Uri address = new Uri("http://localhost:4000/IHelloWCF"); 

        // define how to exchange messages 

        BasicHttpBinding binding = new BasicHttpBinding(); 

        // instantiate a ServiceHost, passing the type to instantiate 

        // when the application receives a message 

        ServiceHost svc = new ServiceHost(typeof(HelloWCF)); 

        // add an endpoint, passing the address, binding, and contract 

        svc.AddServiceEndpoint(typeof(IHelloWCF), binding, address); 

        // begin listening 

        svc.Open(); 

        // indicate that the receiving application is ready and 

        // keep the application from exiting immediately 

        Console.WriteLine("The HelloWCF receiving application is ready"); 

        // wait for incoming messages 

        Console.ReadLine(); 

        // close the service host 

        svc.Close(); 

 } 

 // received messages are dispatched to this instance 

 // method as per the service contract 

 public void Say(String input){ 

        Console.WriteLine("Message received, the body contains: {0}", input); 

public interface IHelloWCF { 

 [OperationContract] 

 void Say(String input); 

改變HelloWCF的類型定義會使得消息的基礎結構分發接受到的消息到服務執行個體的Say操作上,是以會在控制台界面上輸出

一個簡單的語句。

我們現在準備使用下面的指令行編譯并運作這個應用:

C:\temp&gt;csc /nologo /r:"c:\WINDOWS\Microsoft.Net\Framework\v3.0\Windows Communication 

Foundation\System.ServiceModel.dll" HelloWCFApp.cs 

C:\temp&gt;HelloWCFApp.exe 

The HelloWCF receiving application is ready

此時,接受消息的應用在被動地等待請求消息的到來。我們是用netstat.exe可以檢查一下應用是否确實在偵聽,如下所示:

c:\temp&gt;netstat –a –bTCP        kermit:4000                        0.0.0.0:0                            LISTENING             1104[HelloWCFApp.exe]

其實在這個例子裡你可以看到更多的輸入資訊,但是你将會看到2行與此類似的結果(我的電腦名字是Kermit)。

發送消息的基礎結構也需要依靠位址、綁定和契約,這與接收消息的基礎結構類似。非常典型的是發送者使用的位址、綁定和

契約和接受者。

與接受者不同,發送代碼使用的是不同的類型。概念上,這樣非常有用,因為發送者和接受者在消息交換中扮演着不同的角色。放棄直接使用Uri類型,絕大多數接受者使用System.Service-Model.EndpointAddress類型去表示消息發送的目标。你将在第5章:消息裡看到,EndpointAddress類型是WCF對于WS-Addressing 終結點參考的抽象。此外,發送者不使用ServiceHost類型,而是使用ChannelFactory&lt;T&gt;類型(T是服務契約類型)。ChannelFactory&lt;T&gt;類型建構發送消息的基礎結構和ServiceHost建構接受消息的基礎結構類似。下面的代碼示範了如何使用EndpointAddress類型和ChannelFactory&lt;T&gt;建構發送基礎結構。

        // begin the sender code發送者代碼開始 

        // create a channelFactory&lt;T&gt; with binding and address 

        ChannelFactory&lt;IHelloWCF&gt; factory = 

            new ChannelFactory&lt;IHelloWCF&gt;(binding, 

                                                                        new EndpointAddress(address)); 

        // use the factory to create a proxy使用工廠建立代理 

        IHelloWCF proxy = factory.CreateChannel(); 

        // use the proxy to send a message to the receiver使用代理發送消息給接受者 

        proxy.Say("Hi there WCF"); 

        // end the sender code發送者代碼結束 

注意到我們調用ChannelFactory&lt;T&gt;執行個體的CreateChannel方法,并且使用其傳回的類型調用我們服務契約的方法。

更高層次上,ChannelFactory&lt;T&gt;對象是一個可以制造産生和發送消息給接受者(是以需要在構造函數裡傳遞綁定和位址)

的基礎結構的類型。ChannelFactory&lt;T&gt;執行個體的CreateChannel方法實際建立的是發送基礎結構,并且通過實作服務契約

的一個對象傳回這個基礎結構的引用。我們可以通過調用服務契約的方法來與發送基礎結構互動,這些都會在本章後面,和

第6章:通道裡詳細介紹。

既然我們已經完成了發送和接受基礎結構代碼,現在應該是編譯和運作程式的時候了,如下所示:

c:\temp&gt;csc /nologo /r:"c:\WINDOWS\Microsoft.Net\Framework\v3.0\Windows Communication 

c:\temp&gt;HelloWCFApp.exe 

The HelloWCF receiving application is ready 

HelloWCF object created 

Message received, the body contains: HelloWCF! 

如期望的一樣,我們的程式執行步驟如下: 

1.        為接受來自http://localhost:4000/IHelloWCF的消息建構基礎結構。 

2.        開始在http://localhost:4000/IHelloWCF上偵聽消息。 

3.        建構發送到http://localhost:4000/IHelloWCF消息的基礎結構。 

4.        生成和發送消息到http://localhost:4000/IHelloWCF。 

5.        接受消息,執行個體化一個HelloWCF對象,分發消息到服務執行個體的Say方法上。 

看一下消息 

現在代碼寫完了,貌似沒看到我們HelloWCF例子裡哪裡使用到了消息。對于開發者,一個WCF應用看起來和感覺都很 

像面向對象或者面向元件的應用。在運作時,WCF應用要生成、發送和接受消息,同樣也要處理消息。通過修改Say 

方法的實作我們能看到WCF接觸結構的消息: 

public void Say(String input){ 

 Console.WriteLine("Message received, the body contains: {0}", input); 

 // Show the contents of the received message顯示接受消息内容 

 Console.WriteLine( 

        OperationContext.Current.RequestContext.RequestMessage.ToString()); 

修改Say方法後的輸出如下: 

&lt;s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt; 

 &lt;s:Header&gt; 

        &lt;To s:mustUnderstand="1" 

                xmlns="http://schemas.microsoft.com/ws/2005/05/adessing/none"&gt; 

            http://localhost:8000/IHelloWCF 

        &lt;/To&gt; 

        &lt;Action s:mustUnderstand="1" 

                        xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"&gt; 

                 http://tempuri.org/IHelloWCF/Say 

             &lt;/Action&gt; 

 &lt;/s:Header&gt; 

 &lt;s:Body&gt; 

        &lt;Say xmlns="http://tempuri.org/"&gt; 

            &lt;input&gt;HelloWCF!&lt;/input&gt; 

        &lt;/Say&gt; 

 &lt;/s:Body&gt; 

&lt;/s:Envelope&gt;

注意到列印的SOAP消息,消息的Body部分包含我們傳遞給局部變量的channel 上Say方法的字元串。宏觀上講,我們的

應用程式使用這個字元來建構一個SOAP消息,然後發送這個SOAP消息到我們程式的接受部分。接受部分,換句話說,它

要接受SOAP消息,建立一個HelloWCF執行個體,提取SOAP Body的内容,調用HelloWCF 執行個體的Say方法,傳遞字元串參數。

WCF基礎結構為我們做了大部分消息處理工作,一般的對象模型都不會揭示我們的WCF程式是如何在發送者和接受者之間

傳遞消息的事實。實際上,從開發者角度來看,我們的程式裡展示的代碼更像是在使用分布式對象程式設計而不是消息應用。

通過修改一行代碼我們能夠很容易地看出HelloWCF程式實際上是一個消息應用,并且我們可以觀察一下這個變化帶來對

消息組成帶來的影響。

BasicHttpBinding binding = new BasicHttpBinding();

變為如下:

WSHttpBinding binding = new WSHttpBinding();

我們會看到如下的輸入:

Creating and sending a message to the receiver 

&lt;s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" 

                        xmlns:s="http://www.w3.org/2003/05/soap-envelope"&gt; 

        &lt;a:Action s:mustUnderstand="1" u:Id="_2" 

                            xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401- 

                            wss-wssecurity-utility-1.0.xsd"&gt; 

             &lt;/a:Action&gt; 

        &lt;a:MessageID u:Id="_3" 

                                 xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis- 

                                 200401-wss-wssecurity-utility-1.0.xsd"&gt; 

            urn:uuid: 

        &lt;/a:MessageID&gt; 

        &lt;a:ReplyTo u:Id="_4" 

                             xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis- 

                             200401-wss-wssecurity-utility-1.0.xsd"&gt; 

            &lt;a:Address&gt;http://www.w3.org/2005/08/addressing/anonymous&lt;/a:Address&gt; 

        &lt;/a:ReplyTo&gt; 

        &lt;a:To s:mustUnderstand="1" u:Id="_5" xmlns:u="http://docs.oasis-open.org/wss/2004/01/ 

oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt; 

        &lt;/a:To&gt; 

        &lt;o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis- 

200401-wss-wssecurity-secext-1.0.xsd"&gt; 

            &lt;u:Timestamp u:Id="uuid--12" 

                                     xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis- 

                                     200401-wss-wssecurity-utility-1.0.xsd"&gt; 

                &lt;u:Created&gt;2006-08-29T01:57:50.296Z&lt;/u:Created&gt; 

                &lt;u:Expires&gt;2006-08-29T02:02:50.296Z&lt;/u:Expires&gt; 

            &lt;/u:Timestamp&gt; 

            &lt;c:SecurityContextToken u:Id="uuid--6" 

xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:u="http://docs.oasis-open.org/wss/ 

2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"&gt; 

                &lt;c:Identifier&gt; 

                    urn:uuid: 

                &lt;/c:Identifier&gt; 

            &lt;/c:SecurityContextToken&gt; 

            &lt;c:DerivedKeyToken 

                 u:Id="uuid--10" 

                 xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" 

                 xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss- 

                 wssecurity-utility-1.0.xsd"&gt; 

                &lt;o:SecurityTokenReference&gt; 

                    &lt;o:Reference 

                        ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" 

                             URI="#uuid--6" /&gt; 

                &lt;/o:SecurityTokenReference&gt; 

                &lt;c:Offset&gt;0&lt;/c:Offset&gt; 

                &lt;c:Length&gt;24&lt;/c:Length&gt; 

                &lt;c:Nonce&gt;A170b1nKz88AuWmWYONX5Q==&lt;/c:Nonce&gt; 

            &lt;/c:DerivedKeyToken&gt; 

                u:Id="uuid--11" 

                xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" 

                xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss- 

                    wssecurity-utility-1.0.xsd"&gt; 

                &lt;c:Nonce&gt;I8M/H2f3vFuGkwZVV1Yw0A==&lt;/c:Nonce&gt; 

            &lt;e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#"&gt; 

                &lt;e:DataReference URI="#_1" /&gt; 

                &lt;e:DataReference URI="#_6" /&gt; 

            &lt;/e:ReferenceList&gt; 

            &lt;e:EncryptedData Id="_6" 

                Type="http://www.w3.org/2001/04/xmlenc#Element" 

                xmlns:e="http://www.w3.org/2001/04/xmlenc#"&gt; 

                &lt;e:EncryptionMethod 

                    Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /&gt; 

                &lt;KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"&gt; 

                    &lt;o:SecurityTokenReference&gt; 

                        &lt;o:Reference 

                            ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" 

                            URI="#uuid--11" /&gt; 

                    &lt;/o:SecurityTokenReference&gt; 

                &lt;/KeyInfo&gt; 

                &lt;e:CipherData&gt; 

                    &lt;e:CipherValue&gt; 

vQ+AT5gioRS6rRiNhWw2UJmvYYZpA+cc1DgC/K+6Dsd2enF4RUcwOG2 

xqfkD/ 

EZkSFRKDzrJYBz8ItHLZjsva4kqfx3UsEJjYPKbxihl2GFrXdPwTmrHWt35Uw0L2rTh8kU9rtj44NfULS59CJbXE6PC7 

Af1qWvnobcPXBqmgm4NA8wwSTuR3IKHPfD/Pg/ 

3WABob534WD4T1DbRr5tXwNr+yQl2nSWN8C0aaP9+LCKymEK7AbeJXAaGoxdGu/ 

t6l7Bw1lBsJeSJmsd4otXcLxt976kBEIjTl8/ 

6SVUd2hmudP2TBGDbCCvgOl4c0vsHmUC1SjXE5vXf6ATkMj6P3o0eMqBiWlG26RWiYBZ3OxnC1fDs60uSvfHtfF8CD0I 

LYGHLgnUHz5CFY0rPomT73RCkCfmgFuheCgB9zHZGtWedY6ivNrZe2KPx0ujQ2Mq4pv4bLns2qoykwK03ma7YGiGExGc 

ZBfkZ2YAkYmHWXJ0Xx4PJmQRAWIKfUCqcrR6lwyLjl5Agsrt0xHA5WEk3hapscW3HZ8wOgwv0fcHlZ1e3EAm0dZr5Ose 

3TAKMXf7FC1tMy5u0763flA6AZk9l7IpAQXcTLYicriH5hzf1416xbTJCtt2rztiItSkYizkiJCUMJLanc6ST5i+GVHz 

J5oRCEWgfOTcQpHmri8y1P1+6jYe9ELla8Mj 

                    &lt;/e:CipherValue&gt; 

                &lt;/e:CipherData&gt; 

            &lt;/e:EncryptedData&gt; 

        &lt;/o:Security&gt; 

 &lt;s:Body u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis- 

        200401-wss-wssecurity-utility-1.0.xsd"&gt; 

.正如你看到的,一個簡單的修改給我們的消息應用生成的消息結構帶來的了巨大的影響。BasicHttpBinding 到WSHttpBinding的轉換使得我們的程式從通過HTTP發送簡單的SOAP消息到通過HTTP發送遵守WS-*規範和編排的複雜消息。這個影響不單單是一個冗長的消息。因為我們的程式現在可以發送和接受基于WS-Security、

WS-SecureConversation和其它消息規範的複雜消息。

注釋:實際上,WCF宏觀程式設計模型去除了“WCF是一個消息應用”的外觀,而提供了更多的分布式對象的“感覺”。在我個人看來,這是平台最大的好處,但是同時充滿了危險。作為開發人員,我們必須抵抗住WCF是分布式對象平台的誘惑,而接受消息的概念。此外,作為一個應用程式和架構的開發人員,我們必須了解如何改變使用WCF類型的方式來影響我們應用系統處理的消息。

我們的Hello WCF程式使用一個相當簡單的方法就實作了接收者和發送者之間的相容性。因為接收者和發送者駐留在同一個AppDo-main裡,并且接收者使用的對象對于發送者來說是可見的,我們在發送者代碼裡簡單地重用了位址、綁定和契約。

在發部分消息應用裡,這個方法是可行的。絕大多數情況,我們希望發送者和接收者去駐留在不同的機器上的AppDomains裡。在這些場景裡,接收者顯示指定消息需求,發送者遵守這些需求。

WS- MetadataExchange規範規定了發送者和接收者在平台無關時如何交換這些資料資訊。在更多的條款裡,WS-MetadataExchange規範限定了友善終結點之間進行消息交換的schema和編排。在大部分現實世界的應用系統裡(或者至

少比我們的Hello WCF程式複雜的應用)。有一個暴露資訊方式的需求,這個方式就是發送者詢問接收者的終結點去提取中繼資料,并使用這些中繼資料建構能發送給接收終結點消息的基礎結構。

預設情況下,我的Hello WCF程式不會暴露任何中繼資料,不會是廣泛接受的Web服務描述語言(WSDL)和擴充 Schema 定義 (XSD)。(不要把消息應用的中繼資料和程式集或者類型中繼資料混淆,即使一個可以用來建立另外一個。)事實上,WCF

預設的情況下不會暴露中繼資料,這些原因都是因為對安全的考慮。中繼資料暴露的資訊包含應用系統的安全需求。以保護秘密的

名義,這個團隊選擇預設情況下關閉這個特性。

如果決定暴露系統的中繼資料,我們可以建構一個暴露中繼資料的終結點,并且建構中繼資料終結點的方式和其它終結點非常相似:

使用位址、綁定和契約。但是目前為止你看到的終結點不太一樣,就是服務契約已經定義到WCF的API裡了。

建構中繼資料終結點的第一步是修改ServiceHost到可以托管中繼資料的狀态。我們可以通過System.ServiceModel. Description.ServiceMetadataBehavior對象增加到ServiceHost行為集合裡。行為是WCF基礎結構用來改變本地消息處理

的特定資訊。下面代碼示範了如何增加ServiceMetadataBehavior對象到活動的ServiceHost對象:

// instantiate a ServiceHost, passing the type to instantiate// when the application receives a messageServiceHost svc = new ServiceHost(typeof(HelloWCF), address); // BEGIN NEW METADATA CODE// create a ServiceMetadataBehavior建立服務中繼資料行為ServiceMetadataBehavior metadata = new ServiceMetadataBehavior();metadata.HttpGetEnabled = true;// add it to the servicehost descriptionsvc.Description.Behaviors.Add(metadata);

// instantiate a ServiceHost, passing the type to instantiate 

// when the application receives a message 

ServiceHost svc = new ServiceHost(typeof(HelloWCF)); 

// BEGIN NEW METADATA CODE 

// create a ServiceMetadataBehavior建立服務中繼資料行為 

ServiceMetadataBehavior metadata = new ServiceMetadataBehavior(); 

// add it to the servicehost description 

svc.Description.Behaviors.Add(metadata); 

// create a TCP metadata binding建立TCP中繼資料綁定 

Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();

由于ASMX(ASP.NET Web Service)的影響,你也許會認為中繼資料隻能通過HTTP傳輸呈現。事實上,中繼資料可以通過多種傳輸協定傳遞,并且WS-MetadataExchange說明了這個靈活性。在我們的例子裡,我們調用CreateMexTcpBinding方法,它傳回了一個繼承自Binding類型的TCP 傳輸綁定。因為我們使用的是TCP傳輸,是以我們必須全包中繼資料位址使用了TCP

位址格式,如下所示:

// create a ServiceMetadataBehavior 

// create a TCP metadata binding 

Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding(); 

// create an address to listen on WS-Metadata exchange traffic 

//建立中繼資料交換偵聽位址 

Uri mexAddress = new Uri("net.tcp://localhost:5000/IHelloWCF/Mex");

既然我們定義了中繼資料終結點需要的位址和綁定,我們要添加終結點到ServiceHost上,方式很像我們定義的第一個消息終結點。當添加中繼資料終結點時,我們要使用WCF API定義的名為System.ServiceModel.Description.IMetadataExchange的服務契約。下面代碼示範了如何添加一個中繼資料終結點到ServiceHost上,使用适當的位址、綁定和契約。

Uri mexAddress = new Uri("net.tcp://localhost:5000/IHelloWCF/Mex"); 

// add the metadata endpoint添加中繼資料終結點 

svc.AddServiceEndpoint(typeof(IMetadataExchange), 

                                             mexBinding, 

                                             mexAddress); 

// END METADATA CODE

如果我們建構和運作 Hello WCF程式,就會看到程式确實在2個不同的位址上偵聽。一個位址是用作服務中繼資料位址,另外

一個位址是為了IHelloWCF.Say功能。讓我們看一下如何從中繼資料終結點提取中繼資料并使用它來建構程式裡的發送端基礎結構。

Microsoft .NET Framework SDK安裝了一個功能強大的工具名字是svcutil.exe,它的一個功能就是詢問一個運作的消息

應用并基于獲得的資訊生成代理。從内部來說,svcutil.exe使用的是WS-MetadataExchange協定,像與ASMX一起普及的WSDL裡的“get”語義一樣。因為我們的接收程式暴露了一個中繼資料終結點,我們可以把svcutil.exe指向這個運作的終結點,svcutil.exe會自動生成一個代理類型和與服務終結點相容的配置資訊,這些資訊都是參考中繼資料生成。當使用這種方式的時候,svcutil.exe 依照WS-MetadataExchange的方式發送消息給接收程式,并轉化這些消息為.NET Framework的類型以

友善發送消息程式的開發。

在你運作svcutil.exe以前,檢查一下HelloWCFApp.exe正常運作并偵聽請求消息。下一步就是打開一個新的Windows SDK指令行視窗,輸入下面的指令:

C:\temp&gt;svcutil /target:code net.tcp://localhost:5000/IHelloWCF/Mex

Svcutil.exe會建立2個檔案:HelloWCFProxy.cs 和output.config。如果你檢查一下HelloWCFProxy.cs檔案,

你就會看到svcutil.exe産生了一個包含IHelloWCF、IHelloWCFChannel,和HelloWCFClient的代碼檔案。

注釋:在svcutil.exe生成的所有類型裡,HelloWCFClient類型是使用最頻繁的。我的觀點是,名稱後面加上Client字尾毫無疑問将會在開發人員裡帶來誤解。毋容置疑,Client言外之意就是Client 和Server。HelloWCFClient類型幫助我們建構消息基礎結構,不似乎傳統的用戶端/伺服器結構。一定要記住,即使它使用Client字尾,我們仍然是建構消息應用。

合起來看,這些類型定義就是幫助我們建立于接受程式相容的發送代碼。注意HelloWCF.cs檔案裡沒有任何接受程式的位址,

也沒有與HelloWCF.cs源檔案比對的綁定。這些資訊都存貯在svcutil.exe生成的另外一個檔案裡(output.config)。WCF提供了豐富的配置選項允許我們來給發送和接受程式通過XML配置檔案定制不同的行為。為了示範如何利用svcutil建立的資料,

讓我們建立另外一個發送消息控制台程式。我們把它命名為HelloWCFSender。這裡我們要重命名一下配置檔案以便新的發送程式可以讀取這個配置檔案(修改為HelloWCFSender.exe.config)。

總之,svcutil.exe為我們的發送程式生成了大部分代碼和配置資訊。建立發送程式與HelloWCF.exe非常相似。

sealed class HelloWCFSender { 

        // wait for the receiver to start 

        Console.WriteLine("Press ENTER when the Receiver is ready"); 

        // print to the console that we are sending a message 

        Console.WriteLine("Sending a message to the Receiver"); 

        // create the HelloWCFClient type created by svcutil 

        HelloWCFClient proxy = new HelloWCFClient(); 

        // invoke the Say method 

        proxy.Say("Hi there from a new Sender"); 

        proxy.Close(); 

        // print to the console that we have sent a message 

        Console.WriteLine("Finished sending a message to the Receiver"); 

注意到我們隻執行個體化了HelloWCFClient類型并調用Say方法。實際複雜的工作都由svcutil.exe生産的類型和WCF配置基礎結構完成了。在我們寫完這些代碼以後,我們可以使用下面的指令編譯為一個程式集:

C:\temp&gt;csc /r: "C:\WINDOWS\Microsoft.Net\v3.0\Windows CommunicationFoundation\System.ServiceModel.dll" HelloWCFProxy.cs HelloWCFSender.cs

接下來我們啟動接受程式(HelloWCFApp.exe),然後啟動發送程式(HelloWCFSender.exe),我們就會在發送端看到下面這樣的輸出消息:

C:\temp&gt;HelloWCFSender.exe 

Press ENTER when the Receiver is ready 

Sending a message to the Receiver 

Finished sending a message to the Receiver

概括地說,我們程式的輸出結果證明了發送部分和以前一樣工作,而沒有重用我們建構接收者部分使用的對象。我們可以檢查接受消息的應用去驗證接收者确實收到了一個新的消息。

既然我們有了2個功能完善的WCF應用,那我們就來從總體上看看WCF的架構。

 本文轉自 frankxulei 51CTO部落格,原文連結:http://blog.51cto.com/frankxulei/318606,如需轉載請自行聯系原作者

繼續閱讀