Vorgehensweise: Erstellen eines Duplexvertrags
Dieses Thema zeigt die grundlegenden Schritte zum Erstellen von Methoden, die einen Duplexvertrag (bidirektionalen Vertrag) verwenden. Ein Duplexvertrag ermöglicht die unabhängige Kommunikation zwischen Clients und Servern, sodass beide Aufrufe des jeweils Anderen initiieren können. Der Duplexvertrag ist eines von drei Nachrichtenmustern, die für Windows Communication Foundation (WCF)-Dienste zur Verfügung stehen. Die anderen beiden Nachrichtenmuster zeichnen sich durch unidirektionale Anforderungen bzw. Antworten aus. Ein Duplexvertrag besteht aus zwei unidirektionalen Verträgen zwischen Client und Server und erfordert nicht, dass die Methodenaufrufe korrelieren. Sie verwenden diese Art von Vertrag, wenn der Dienst vom Client weitere Informationen anfordern muss oder auf dem Client ausdrücklich Ereignisse auslösen muss. Weitere Informationen zum Erstellen einer Clientanwendung für einen Duplexvertrag finden Sie unter Vorgehensweise: Zugreifen auf Dienste mit einem Duplexvertrag. Ein Arbeitsbeispiel finden Sie im Beispiel Duplex-.
So erstellen Sie einen Duplexvertrag
Erstellen Sie die Schnittstelle, die die Serverseite des Duplexvertrags bildet.
Wenden Sie die ServiceContractAttribute-Klasse auf die Schnittstelle an.
[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); }
<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
Deklarieren Sie die Methodensignaturen in der Schnittstelle.
Wenden Sie die OperationContractAttribute-Klasse auf jede Methodensignatur an, die Teil des öffentlichen Vertrags werden muss.
Erstellen Sie die Rückrufschnittstelle, mit der die Vorgänge definiert werden, die vom Dienst auf dem Clientendpunkt aufgerufen werden können.
public interface ICalculatorDuplexCallback { [OperationContract(IsOneWay = true)] void Equals(double result); [OperationContract(IsOneWay = true)] void Equation(string eqn); }
Public Interface ICalculatorDuplexCallback <OperationContract(IsOneWay:=True)> _ Sub Equals(ByVal result As Double) <OperationContract(IsOneWay:=True)> _ Sub Equation(ByVal eqn As String) end interface
Deklarieren Sie die Methodesignaturen in der Rückrufschnittstelle.
Wenden Sie die OperationContractAttribute-Klasse auf jede Methodensignatur an, die Teil des öffentlichen Vertrags werden muss.
Verknüpfen Sie die beiden Schnittstellen zu einem Duplexvertrag, indem Sie die CallbackContract-Eigenschaft der primären Schnittstelle auf den Typ der Rückrufschnittstelle festlegen.
So rufen Sie Methoden auf dem Client auf
Deklarieren Sie in der Dienstimplementierung des primären Vertrags eine Variable für die Rückrufschnittstelle.
Legen Sie die Variable auf den von der GetCallbackChannel-Methode der OperationContext-Klasse zurückgegebenen Objektverweis fest.
ICalculatorDuplexCallback callback = null;
Dim callback As ICalculatorDuplexCallback
callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
callback = OperationContext.Current.GetCallbackChannel(Of ICalculatorDuplexCallback)()
Rufen Sie die in der Rückrufschnittstelle definierten Methoden auf.
Beispiel
Der folgende Beispielcode veranschaulicht die Duplexkommunikation. Der Vertrag des Diensts enthält Dienstvorgänge zum vorwärts- und rückwärtsgerichteten Navigieren. Der Vertrag des Clients enthält einen Dienstvorgang zur Ausgabe seiner Position.
// Define a duplex service contract.
// A duplex contract consists of two interfaces.
// The primary interface is used to send messages from client to service.
// The callback interface is used to send messages from service back to client.
// ICalculatorDuplex allows one to perform multiple operations on a running result.
// The result is sent back after each operation on the ICalculatorCallback 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);
}
// The callback interface is used to send messages from service back to client.
// The Equals operation will return the current result after each operation.
// The Equation operation will return the complete equation after Clear() is called.
public interface ICalculatorDuplexCallback
{
[OperationContract(IsOneWay = true)]
void Equals(double result);
[OperationContract(IsOneWay = true)]
void Equation(string eqn);
}
// Service class which implements a duplex service contract.
// Use an InstanceContextMode of PerSession to store the result
// An instance of the service will be bound to each duplex session
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class CalculatorService : ICalculatorDuplex
{
double result;
string equation;
ICalculatorDuplexCallback callback = null;
public CalculatorService()
{
result = 0.0D;
equation = result.ToString();
callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
}
public void Clear()
{
callback.Equation(equation + " = " + result.ToString());
result = 0.0D;
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);
}
}
' Define a duplex service contract.
' A duplex contract consists of two interfaces.
' The primary interface is used to send messages from client to service.
' The callback interface is used to send messages from service back to client.
' ICalculatorDuplex allows one to perform multiple operations on a running result.
' The result is sent back after each operation on the ICalculatorCallback interface.
<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
' The callback interface is used to send messages from service back to client.
' The Equals operation will return the current result after each operation.
' The Equation operation will return the complete equation after Clear() is called.
Public Interface ICalculatorDuplexCallback
<OperationContract(IsOneWay:=True)> _
Sub Equals(ByVal result As Double)
<OperationContract(IsOneWay:=True)> _
Sub Equation(ByVal eqn As String)
end interface
' Service class which implements a duplex service contract.
' Use an InstanceContextMode of PerSession to store the result
' An instance of the service will be bound to each duplex session
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession)> _
Public Class CalculatorService
Implements ICalculatorDuplex
Dim result As Double
Dim equation As String
Dim callback As ICalculatorDuplexCallback
Public Sub New()
result = 0D
equation = result.ToString()
callback = OperationContext.Current.GetCallbackChannel(Of ICalculatorDuplexCallback)()
End Sub
Public Sub AddTo(ByVal n As Double) Implements ICalculatorDuplex.AddTo
result += n
equation += " + " + n.ToString()
callback.Equals(result)
End Sub
Public Sub Clear() Implements ICalculatorDuplex.Clear
callback.Equation(equation + " = " + result.ToString())
result = 0D
equation = result.ToString()
End Sub
Public Sub DivideBy(ByVal n As Double) Implements ICalculatorDuplex.DivideBy
result /= n
equation += " / " + n.ToString()
callback.Equals(result)
End Sub
Public Sub MultiplyBy(ByVal n As Double) Implements ICalculatorDuplex.MultiplyBy
result *= n
equation += " * " + n.ToString()
callback.Equals(result)
End Sub
Public Sub SubtractFrom(ByVal n As Double) Implements ICalculatorDuplex.SubtractFrom
result -= n
equation += " - " + n.ToString()
callback.Equals(result)
End Sub
End Class
Durch Anwenden des ServiceContractAttribute-Attributs und des OperationContractAttribute-Attributs wird die automatische Generierung von Dienstvertragsdefinitionen in WSDL (Web Services Description Language) ermöglicht.
Verwenden Sie das ServiceModel Metadata Utility Tool (Svcutil.exe), um das WSDL-Dokument und (optional) Den Code und die Konfiguration für einen Client abzurufen.
Endpunkte, die Duplexdienste verfügbar machen, müssen geschützt werden. Wenn ein Dienst eine Duplexnachricht empfängt, überprüft er das ReplyTo-Element in dieser eingehenden Nachricht, um zu bestimmen, wohin die Antwort gesendet werden soll. Wenn der zum Empfangen der Nachricht verwendete Kanal nicht geschützt ist, kann ein nicht vertrauenswürdiger Client eine bösartige Meldung mit dem ReplyTo-Element eines Zielcomputers senden, was auf diesem Zielcomputer zu einem Denial Of Service (DOS) führt. Bei gewöhnlichen Anforderung-Antwort-Nachrichten stellt dies kein Problem dar, weil das ReplyTo-Element ignoriert und die Antwort auf dem Kanal gesendet wird, auf dem die ursprüngliche Nachricht empfangen wurde.