[WCF編程]10.操做:單向操做

1、單向操做概述

        WCF提供了單向操做,一旦客戶端調用,WCF會生成一個請求,但沒有相關的應答信息返回給客戶端。因此,單向操做是不能有返回值,服務拋出的任何異常都不會傳遞給客戶端。安全

        理想狀況下,一旦客戶端調用了一個單向操做,它只會在要求調用的一瞬間被阻塞。事實上,單向調用不等於異步調用。當單向調用到達服務端時,不會當即分發這些調用,而是將調用方法服務端的隊列中,並在某個時間分發。這一過程要根據服務配置的併發模式行爲而定。服務要放入到隊列中的消息個數與哦誒只的管道及可靠性模式有關。若是隊列消息的數量超過了隊列的容量,即便發出的只是單向調用,也會阻塞客戶端。然而,一旦調用被放入隊列中,就會取消對客戶端的阻塞,繼續執行。同時,服務會在後臺處理這一操做。多線程

        開發人員容易錯誤的認爲單向操做等於併發調用。若是客戶端使用了相同的代理,但卻利用了多線程調用單向操做,則在服務端的調用多是併發,也可能不是。從本質上將,這種交互式是由服務併發管理模式和傳輸會話所決定的。併發

        全部的WCF綁定都支持單向操做。異步

2、配置單向操做

        OperationContract特性定義了Boolean類型的IsOneWay屬性:ui

public sealed class OperationContractAttribute : Attribute
{
   public bool IsOneWay { get; set; }
}

        IsOneWay屬性的默認值爲false,即默認操做爲請求/應答操做,若是將IsOneWay屬性設置爲true,方法就會成爲單向操做。spa

[ServiceContract]
 public interface IService7
 {
    [OperationContract(IsOneWay=true)]
    void MyMethod();
 }

        調用單向操做時,客戶端並沒有任何特別之初。IsOneWay屬性的值會包含在服務元數據中。注意,服務契約定義與客戶端導入定義中的IsOneWay的值是相同的。線程

        因爲單向操做沒有應答消息,所以它不能包含返回值。以下所示:設計

[ServiceContract]
 public interface IService7
 {
    [OperationContract(IsOneWay=true)]
    void MyMethod();
 }

        事實上,在加載宿主或打開代理時,WCF會強制要求驗證方法的簽名。代理

3、單向操做和可靠性

        客戶端不關心調用的結果,並不意味着它不關心調用是否發生。總而言之,即便採用了單向操做,也必須保證服務的可靠性,使他可以確保請求正確的傳遞到服務。code

        但客戶端不會考慮單向操做的調用順序,這也是WCF容許開發者將有效的可靠性傳遞從有效的有序傳遞與消息的執行中分離出來的主要緣由。

4、單向操做與會話服務

        WCF容許開發者設計一個具備單向操做的會話契約:

[ServiceContract(SessionMode=SessionMode.Required)]
public interface IService7
{
    [OperationContract(IsOneWay=true)]
    void MyMethod();
}

        在這種配置下,若是客戶端發出一個單向操做,則在執行方法時會關閉代理,而後阻塞客戶端直到操做完成。

        雖然技術上可行,可是在一個會話契約中包含一個單向操做是一種糟糕的設計。由於擁有一個會話每每意味着服務須要管理表明了客戶端的狀態。任何異常均可能破壞這個狀態,而這時的客戶端取沒法獲取異常。此外,客戶端或服務之因此選擇一個會話交互,是由於它使用的契約須要經過某個狀態機 完成鎖步執行。單調操做沒法知足這種模式的要求。因此建議只能將單向操做應用到單向服務或者單例服務中。

        若是在會話契約中定義了單向操做,就必須保證單向操做是終止會話的最後一個操做。這個能夠經過分佈操做來實現:

[ServiceContract(SessionMode=SessionMode.Required)]
public interface IService7
{
    [OperationContract()]
    void MyMethod();
    [OperationContract(IsOneWay = true,IsInitiating=false,IsTerminating=true)]
    void Over();
}

5、單向操做與異常

        即便單向操做沒有返回值,也不會從服務端返回異常,但客戶端仍然須要得到單向調用的異常,設置推斷調用在服務段已經失敗。

        若是沒有傳輸會話(使用BasicHttpBingding綁定或不包含可靠消息傳輸與安全的WsHttpBingding綁定),在調用一個單向操做期間,若是發生異常,客戶端並不會受到影響,會繼續發出對相同代理實例的調用:

[ServiceContract]
public interface IService7
{
    [OperationContract(IsOneWay =true)]
    void MethodWithError();
    [OperationContract]
    void MethodWithoutError();
}

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,ConcurrencyMode=ConcurrencyMode.Single)]
public class Service7:IService7
{
    public void MethodWithError()
    {
        throw new Exception();
    }
    public void MethodWithoutError()
    {
         
     }
}
//不具備傳輸會話
MyContractClient proxy = new MyContractClient();
proxy.MethodWithError();
proxy.MethodWithoutError();
proxy.Close();

        若是存在傳輸會話,那麼一個服務端的異常(包含單向操做拋出的異常)就會操做通道錯誤。此時,客戶端不能發出任何一個使用相同代理實例的新的調用。

[ServiceContract]
public interface IService7
{
    [OperationContract(IsOneWay =true)]
    void MethodWithError();
    [OperationContract]
    void MethodWithoutError();
}

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall,ConcurrencyMode=ConcurrencyMode.Single)]
public class Service7:IService7
{
    public void MethodWithError()
    {
        throw new Exception();
    }
    public void MethodWithoutError()
    {
         
     }
}
//具備傳輸會話
MyContractClient proxy = new MyContractClient();
proxy.MethodWithError();
try
{
proxy.MethodWithoutError();//由於通道錯誤,從而會被拋出
proxy.Close();
}
catch
{}

        客戶端甚至不能安全地關閉代理。所以,單向操做並不具有即發即棄的特性,由於客戶端在調用期間會發現服務端出現的錯誤。

        之後會展現如何真正的異步即發即棄的操做使用單向操做。

相關文章
相關標籤/搜索