双方向サービス コントラクトは、両方のエンドポイントが互いに独立してメッセージを送信できるメッセージ交換パターンです。 したがって、双方向サービスは、イベントのような動作を提供して、クライアント エンドポイントにメッセージを送信できます。 双方向通信は、クライアントがサービスに接続し、サービスがクライアントにメッセージを送信できるチャネルをサービスに提供するときに発生します。 双方向サービスのイベントに似た動作は、セッション内でのみ機能します。
双方向コントラクトを作成するには、インターフェイスのペアを作成します。 1 つ目は、クライアントが呼び出すことができる操作を記述するサービス コントラクト インターフェイスです。 そのサービス コントラクトでは、ServiceContractAttribute.CallbackContract プロパティでコールバック コントラクトを指定する必要があります。 コールバック コントラクトは、サービスがクライアント エンドポイントで呼び出すことができる操作を定義するインターフェイスです。 双方向コントラクトではセッションは必要ありませんが、システム提供の双方向バインディングではセッションが使用されます。
二重コントラクトの例を次に示します。
[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);
}
<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
CalculatorService
クラスは、プライマリ ICalculatorDuplex
インターフェイスを実装します。 サービスは、 PerSession インスタンス モードを使用して、各セッションの結果を維持します。
Callback
という名前のプライベート プロパティは、クライアントへのコールバック チャネルにアクセスします。 このサービスは、次のサンプル コードに示すように、コールバック インターフェイスを介してクライアントにメッセージを送信するためにコールバックを使用します。
[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>();
}
}
}
<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
クライアントは、サービスからメッセージを受信するために、双方向コントラクトのコールバック インターフェイスを実装するクラスを提供する必要があります。 次のサンプル コードは、ICalculatorDuplexCallback
インターフェイスを実装するCallbackHandler
クラスを示しています。
public class CallbackHandler : ICalculatorDuplexCallback
{
public void Equals(double result)
{
Console.WriteLine($"Equals({result})");
}
public void Equation(string eqn)
{
Console.WriteLine($"Equation({eqn})");
}
}
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
二重コントラクト用に生成される WCF クライアントでは、構築時に InstanceContext クラスを指定する必要があります。 この InstanceContext クラスは、コールバック インターフェイスを実装し、サービスから返されるメッセージを処理するオブジェクトのサイトとして使用されます。
InstanceContext クラスは、CallbackHandler
クラスのインスタンスを使用して構築されます。 このオブジェクトは、コールバック インターフェイスでサービスからクライアントに送信されたメッセージを処理します。
// Construct InstanceContext to handle messages on callback interface
InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
// Create a client
CalculatorDuplexClient client = new CalculatorDuplexClient(instanceContext);
' Construct InstanceContext to handle messages on callback interface
Dim instanceContext As New InstanceContext(New CallbackHandler())
' Create a client
Dim client As New CalculatorDuplexClient(instanceContext)
サービスの構成は、セッション通信と双方向通信の両方をサポートするバインディングを提供するように設定する必要があります。
wsDualHttpBinding
要素は、セッション通信をサポートし、双方向通信を可能にします。双方向の HTTP 接続は、方向ごとに 1 つずつ提供されます。
クライアントでは、次のサンプル構成に示すように、サーバーがクライアントへの接続に使用できるアドレスを構成する必要があります。
注
セキュリティで保護された会話を使用して認証に失敗する非二重クライアントは、通常、 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("http://localhost:12000/DuplexTestUsingCode/Server");
binding.ClientBaseAddress = new Uri("http://localhost:8000/DuplexTestUsingCode/Client/");
Dim binding As New WSDualHttpBinding()
Dim endptadr As New EndpointAddress("http://localhost:12000/DuplexTestUsingCode/Server")
binding.ClientBaseAddress = New Uri("http://localhost:8000/DuplexTestUsingCode/Client/")
次のサンプル コードは、構成でクライアント エンドポイント アドレスを指定する方法を示しています。
<client>
<endpoint name ="ServerEndpoint"
address="http://localhost:12000/DuplexTestUsingConfig/Server"
bindingConfiguration="WSDualHttpBinding_IDuplexTest"
binding="wsDualHttpBinding"
contract="IDuplexTest" />
</client>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IDuplexTest"
clientBaseAddress="http://localhost:8000/myClient/" >
<security mode="None"/>
</binding>
</wsDualHttpBinding>
</bindings>
Warnung
サービスまたはクライアントがチャネルを閉じると、双方向モデルは自動的に検出されません。 そのため、クライアントが予期せず終了した場合、既定ではサービスには通知されません。または、サービスが予期せず終了した場合、クライアントには通知されません。 切断されたサービスを使用すると、 CommunicationException 例外が発生します。 クライアントとサービスは、独自のプロトコルを実装して、選択した場合に互いに通知することができます。 エラー処理の詳細については、「 WCF エラー処理」を参照してください。