共用方式為


雙工服務

雙工服務合約為訊息交換模式,其中的兩個端點可以彼此獨立地傳送訊息。因此,雙工服務可以將訊息傳送回用戶端端點,以提供類似事件的行為。用戶端建立與服務的連線,並提供服務所需的通道以供服務將訊息傳回用戶端,這個程序即是所謂的雙工通訊。請注意,雙工服務的類似事件行為只會在工作階段內運作。

若要建立雙工合約,您可建立一組介面。第一個是服務合約介面,說明用戶端可叫用的作業。該服務合約必須在 System.ServiceModel.ServiceContractAttribute.CallbackContract 屬性中指定「回呼合約」(Callback Contract)。回呼合約是一個介面,會定義服務可在用戶端端點上呼叫的作業。雙工合約不需要工作階段,不過系統提供的雙工繫結會利用工作階段。

以下為雙工合約的範例。

<ServiceContract(Namespace := "http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required, CallbackContract:=GetType(ICalculatorDuplexCallback))> _
Public Interface ICalculatorDuplex
    <OperationContract(IsOneWay := True)> _
    Sub Clear()
    <OperationContract(IsOneWay := True)> _
    Sub AddTo(ByVal n As Double)
    <OperationContract(IsOneWay := True)> _
    Sub SubtractFrom(ByVal n As Double)
    <OperationContract(IsOneWay := True)> _
    Sub MultiplyBy(ByVal n As Double)
    <OperationContract(IsOneWay := True)> _
    Sub DivideBy(ByVal n As Double)
End Interface


Public Interface ICalculatorDuplexCallback
    <OperationContract(IsOneWay := True)> _
    Sub Equals(ByVal result As Double)
    <OperationContract(IsOneWay := True)> _
    Sub Equation(ByVal eqn As String)
End Interface
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required,
                 CallbackContract=typeof(ICalculatorDuplexCallback))]
public interface ICalculatorDuplex
{
    [OperationContract(IsOneWay = true)]
    void Clear();
    [OperationContract(IsOneWay = true)]
    void AddTo(double n);
    [OperationContract(IsOneWay = true)]
    void SubtractFrom(double n);
    [OperationContract(IsOneWay = true)]
    void MultiplyBy(double n);
    [OperationContract(IsOneWay = true)]
    void DivideBy(double n);
}


public interface ICalculatorDuplexCallback
{
    [OperationContract(IsOneWay = true)]
    void Equals(double result);
    [OperationContract(IsOneWay = true)]
    void Equation(string eqn);
}

CalculatorService 類別會實作主要的 ICalculatorDuplex 介面。服務會使用 PerSession 執行個體模式維持各工作階段的結果。而名為 Callback 的私用屬性會存取用戶端的回呼通道。服務會使用回呼,以透過回呼介面將訊息傳回用戶端,如以下範例程式碼所示。

<ServiceBehavior(InstanceContextMode := InstanceContextMode.PerSession)> _
Public Class CalculatorService
    Implements ICalculatorDuplex
    Private result As Double = 0.0R
    Private equation As String

    Public Sub New()
        equation = result.ToString()
    End Sub

    Public Sub Clear() Implements ICalculatorDuplex.Clear
        Callback.Equation(equation & " = " & result.ToString())
        equation = result.ToString()
    End Sub

    Public Sub AddTo(ByVal n As Double) Implements ICalculatorDuplex.AddTo
        result += n
        equation &= " + " & n.ToString()
        CType(Callback, Object).Equals(result)
    End Sub

    Public Sub SubtractFrom(ByVal n As Double) Implements ICalculatorDuplex.SubtractFrom
        result -= n
        equation &= " - " & n.ToString()
        CType(Callback, Object).Equals(result)
    End Sub

    Public Sub MultiplyBy(ByVal n As Double) Implements ICalculatorDuplex.MultiplyBy
        result *= n
        equation &= " * " & n.ToString()
        CType(Callback, Object).Equals(result)
    End Sub

    Public Sub DivideBy(ByVal n As Double) Implements ICalculatorDuplex.DivideBy
        result /= n
        equation &= " / " & n.ToString()
        CType(Callback, Object).Equals(result)
    End Sub

    Private ReadOnly Property Callback() As ICalculatorDuplexCallback
        Get
            Return OperationContext.Current.GetCallbackChannel(Of ICalculatorDuplexCallback)()
        End Get
    End Property
End Class
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class CalculatorService : ICalculatorDuplex
{
    double result = 0.0D;
    string equation;

    public CalculatorService()
    {
        equation = result.ToString();
    }

    public void Clear()
    {
        Callback.Equation(equation + " = " + result.ToString());
        equation = result.ToString();
    }

    public void AddTo(double n)
    {
        result += n;
        equation += " + " + n.ToString();
        Callback.Equals(result);
    }

    public void SubtractFrom(double n)
    {
        result -= n;
        equation += " - " + n.ToString();
        Callback.Equals(result);
    }

    public void MultiplyBy(double n)
    {
        result *= n;
        equation += " * " + n.ToString();
        Callback.Equals(result);
    }

    public void DivideBy(double n)
    {
        result /= n;
        equation += " / " + n.ToString();
        Callback.Equals(result);
    }

    ICalculatorDuplexCallback Callback
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
        }
    }
}

用戶端必須提供實作雙工合約回呼介面的類別,用於接收來自服務的訊息。以下範例程式碼將示範實作 ICalculatorDuplexCallback 介面的 CallbackHandler 類別。

Public Class CallbackHandler
    Implements ICalculatorDuplexCallback
    Public Overridable Shadows Sub Equals(ByVal result As Double) Implements ICalculatorDuplexCallback.Equals
        Console.WriteLine("Equals({0})", result)
    End Sub

    Public Sub Equation(ByVal eqn As String) Implements ICalculatorDuplexCallback.Equation
        Console.WriteLine("Equation({0})", eqn)
    End Sub
End Class
public class CallbackHandler : ICalculatorDuplexCallback
{
    public void Equals(double result)
    {
        Console.WriteLine("Equals({0})", result);
    }

    public void Equation(string eqn)
    {
        Console.WriteLine("Equation({0})", eqn);
    }
}

針對雙工合約所產生的 WCF 用戶端,會要求在建構時提供 InstanceContext 類別。這個 InstanceContext 類別會用來做為站台,讓物件實作回呼介面並處理服務傳回的訊息。InstanceContext 類別是以 CallbackHandler 類別的執行個體所建構。這個物件會處理回呼介面上,從服務傳回至用戶端的訊息。

' Construct InstanceContext to handle messages on callback interface
Dim instanceContext As New InstanceContext(New CallbackHandler())

' Create a client
Dim client As New CalculatorDuplexClient(instanceContext)
// Construct InstanceContext to handle messages on callback interface
InstanceContext instanceContext = new InstanceContext(new CallbackHandler());

// Create a client
CalculatorDuplexClient client = new CalculatorDuplexClient(instanceContext);

服務的組態必須進行設定,以提供同時支援工作階段通訊和雙工通訊的繫結。wsDualHttpBinding 項目支援工作階段通訊,並且藉由提供雙重 HTTP 連接 (一個方向一個連接) 允許雙工通訊。

在用戶端上,您必須設定伺服器可用來連接用戶端的位址,如下面的範例組態中所示。

ms731064.note(zh-tw,VS.100).gif注意:
無法使用安全對話來進行驗證的非雙工用戶端通常會擲回 MessageSecurityException。不過,如果使用安全對話的雙工用戶端驗證失敗,則用戶端會收到 TimeoutException

如果您使用 WSHttpBinding 項目建立用戶端/服務,但是未包含用戶端回呼端點,則會收到以下錯誤。

HTTP could not register URL
htp://+:80/Temporary_Listen_Addresses/<guid> because TCP port 80 is being used by another application.

以下範例程式碼將示範如何在程式碼中指定用戶端端點位址。

WSDualHttpBinding binding = new WSDualHttpBinding();
EndpointAddress endptadr = new EndpointAddress("https://localhost:12000/DuplexTestUsingCode/Server");
binding.ClientBaseAddress = new Uri("https://localhost:8000/DuplexTestUsingCode/Client/");

以下範例程式碼將示範如何在組態中指定用戶端端點位址。

<client>
    <endpoint name ="ServerEndpoint" 
          address="https://localhost:12000/DuplexTestUsingConfig/Server"
          bindingConfiguration="WSDualHttpBinding_IDuplexTest" 
            binding="wsDualHttpBinding"
           contract="IDuplexTest" />
</client>
<bindings>
    <wsDualHttpBinding>
        <binding name="WSDualHttpBinding_IDuplexTest"  
          clientBaseAddress="https://localhost:8000/myClient/" >
            <security mode="None"/>
         </binding>
    </wsDualHttpBinding>
</bindings>
ms731064.Warning(zh-tw,VS.100).gif 注意:
此雙工模型不會自動偵測服務或用戶端關閉其通道的時間。因此,如果某個服務意外終止,預設不會通知此服務,或者如果某個用戶端意外終止,也不會通知此服務。用戶端和服務可以實作自己的通訊協定來通知彼此 (如果選擇這樣做的話)。

另請參閱

工作

雙工
HOW TO:建立通道處理站並使用它來建立與管理通道

概念

指定用戶端執行階段行為