[老老實實學WCF] 第九篇 消息通信模式(上) 請求應答與單向

老老實實學WCF

第九篇 消息通信模式(上) 請求應答與單向

 

通過前兩篇的學習,我們瞭解了服務模型的一些特性如會話和實例化,今天我們來進一步學習服務模型的另一個重要特性:消息通信模式。

 

WCF的服務端與客戶端在通信時有三種模式:單向模式、請求/應答模式和雙工模式。

 

如果選用了單向模式,調用方在向被調用方進行了調用後不期待任何迴應,被調用方在執行完調用後不給調用方任何反饋。如客戶端通過單向模式調用了一個服務端的操作後,就去幹別的了,不會等待服務端給他任何響應,他也無從得知調用是否成功,甚至連發生了錯誤也全然不知。這種模式的特點是,客戶端在調用操作後立即返回,從客戶端角度看,用戶操作的響應是非常快的,只是客戶端無法得知調用結果。

 

如果選用了請求/應答模式,客戶端向服務端發出調用後會一直等待服務端的回覆,服務端在執行完操作後會把結果返回給客戶端,即使服務操作簽名返回值爲void,服務端還是會返回一條空消息,告訴客戶端調用完成了,客戶端在接到返回後纔會從調用方法返回繼續進行下面的工作。這種模式的特點是客戶端總是可以知道服務執行的情況,如果出錯,錯誤也會返回,客戶端對服務的執行監控的很好,但是由於在服務返回之前客戶端會一直等待,所以如果服務端的服務執行時間比較長的話,客戶端這邊的用戶響應就會很慢,如果客戶端對服務的調用與用戶界面在同一線程,在用戶看來,應用程序就死在那裏了。

 

如果選用了雙工模式,客戶端和服務端都可以單獨的向對方發送消息調用,其實這種模式是在單向模式基礎上進行的,兩邊的調用都是單向調用,但是兩邊都可以獨立的進行,誰也不用等待誰,這種模式比較複雜一些,我們在下一篇再詳細的研究。

 

1. 如何設置消息通信模式。

雙工模式有其他的設置方式,單行模式和請求應答模式的設置位置是相同的,就是通過修改操作協定的OperationContract屬性的IsOneWay屬性來設置。如下面的代碼將HelloWCF操作協定設置爲了單向模式:

    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=true)]
        void HelloWCF();
    }  

如果不配置IsOneWay屬性,那麼他默認是False的,也就是說默認的消息通信模式是請求/應答模式,除非我們顯式的指定爲單向模式。

下面的代碼將HelloWCF操作協定設置爲了請求/應答模式:

    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=false)]
        void HelloWCF();
    }  

由於是默認值,IsOneWay屬性不配置也是可以的。

 

注意,在單向模式下,返回值必須是void,並且不能使用任何Out或Ref的方式返回參數值,也就是說不能以任何手段返回任何值,這是基礎結構所不允許的,這樣做會導致服務端拋出異常。而在請求/應答模式下,這些都是可以的,即使沒有返回值(返回值爲void),返回消息也會照樣發送,只不過是個空消息。

2. 兩種模式的例子

首先我們看一個請求/應答模式的例子,我用的還是前幾篇中使用的IIS宿主服務的例子,如果你忘了,翻回去熟悉一下。

我們讓服務端的HelloWCF在返回"Hello WCF!"字符串之前,先磨蹭一會,讓他在線程上休眠一會兒。

HelloWCFService.CS的源代碼如下:

using System;
using System.ServiceModel;

namespace LearnWCF
{
    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=false)]
        string HelloWCF();
    }  

    public class HelloWCFService : IHelloWCF
    {
        private int _Counter;
        public string HelloWCF()
        {
            System.Threading.Thread.Sleep(3000);
            return "Hello WCF!";
        }
    }
}

沒什麼變化,就是讓他在線程上Sleep 3秒。

下面是Web.Config文件,也沒什麼變化:

<configuration>
  <system.serviceModel>
    <services>
      <service name="LearnWCF.HelloWCFService" behaviorConfiguration="metadataExchange">
        <endpoint address="" binding="wsHttpBinding" contract="LearnWCF.IHelloWCF"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metadataExchange">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

下面是SVC文件,就一行代碼,指示了這是個WCF服務,並指定了後臺類型:

<%@ServiceHost language=c# Debug="true" Service="LearnWCF.HelloWCFService"%>

 

把SVC文件和Web.Config文件放在網站根文件夾下,CS文件放在App_Code文件夾下,啓動IIS,服務就寄宿好了,如果你忘記了如何在IIS中寄宿,馬上翻回第三篇熟悉一下。

 

用SVCUTIL.EXE或添加服務引用來生成客戶端,爲了能看出調用的時間,我們在調用前和調用後分別把時間輸出來。Program.cs代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Services.HelloWCFClient client = new Services.HelloWCFClient();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            Console.WriteLine(client.HelloWCF());
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            Console.ReadLine();
        }
    }
}

F5運行一下,結果如下:

可以看到,整個調用花費了4秒鐘,除了服務方法中Sleep了3秒,建立會話通訊什麼的還用了1秒,在服務端方法Sleep的時候,客戶端一直在等待。

 

接下來,我們再看單向模式的情況,我們修改一下服務協定的代碼,讓其採用單向模式,但是注意,此時不能有返回值了,必須設爲void,服務方法中就是睡3秒,其他的什麼也不做。

using System;
using System.ServiceModel;

namespace LearnWCF
{
    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=true)]
        void HelloWCF();
    }  

    public class HelloWCFService : IHelloWCF
    {
        private int _Counter;
        public void HelloWCF()
        {
            System.Threading.Thread.Sleep(3000);
        }
    }
}


客戶端需要重新下載一下元數據或更新一下服務引用,因爲服務協定的內容變了,客戶端Program.CS代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Services.HelloWCFClient client = new Services.HelloWCFClient();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            client.HelloWCF();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            Console.ReadLine();
        }
    }
}


F5看看結果:

可以看到只用了1秒,客戶端與服務端建立會話後把調用送出就立即返回了,沒有等待服務端睡那三秒,當然此時的客戶端也根本就不知道服務端在做什麼。

 

注意,請求應答模式是需要會話支持的,必須使用支持會話的綁定,而且服務協定的SessionMode必須至少爲Allowed,服務類的ServiceBehavior的InstanceContextMode必須是PerSession,我們在這裏沒有配置,因爲他們是默認的,但是我們必須知道他們需要這樣的配置才能支持請求/應答模式。

 

如果你在試驗中遇到了莫名其妙的問題,嘗試把客戶端服務引用全部刪掉重新添加服務引用,因爲有的時候更新服務引用不總是那麼好用。

3. 總結

通過這一篇的學習,我們瞭解了消息通訊的兩種基本模式,在這個基礎上還有更加複雜的雙工通訊模式,我們在下一篇中詳細研究。







 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章