DuplexdiensteDuplex Services

Bei einem Duplexdienstvertrag handelt es sich um ein Nachrichtenaustauschmuster, bei dem beide Endpunkte eigenständig Nachrichten an den jeweils anderen Endpunkt senden können.A duplex service contract is a message exchange pattern in which both endpoints can send messages to the other independently. Daher kann ein Duplexdienst Nachrichten zurück an den Clientendpunkt senden und so ein ereignisähnliches Verhalten bereitstellen.A duplex service, therefore, can send messages back to the client endpoint, providing event-like behavior. Eine Duplexkommunikation findet statt, wenn ein Client eine Verbindung mit einem Dienst herstellt und dem Dienst einen Kanal bereitstellt, über den dieser Nachrichten zurück an den Client senden kann.Duplex communication occurs when a client connects to a service and provides the service with a channel on which the service can send messages back to the client. Beachten Sie, dass Duplexdienste nur innerhalb einer Sitzung ein ereignisähnliches Verhalten zeigen.Note that the event-like behavior of duplex services only works within a session.

Um einen Duplexvertrag einzurichten, erstellen Sie zwei Schnittstellen.To create a duplex contract you create a pair of interfaces. Bei der ersten handelt es sich um die Dienstvertragschnittstelle, mit der die Vorgänge beschrieben werden, die von einem Client implementiert werden können.The first is the service contract interface that describes the operations that a client can invoke. Dieser Dienstvertrag muss Geben Sie einen Rückrufvertrag in der ServiceContractAttribute.CallbackContract Eigenschaft.That service contract must specify a callback contract in the ServiceContractAttribute.CallbackContract property. Der Rückrufvertrag wiederum ist die Schnittstelle, mit der die Vorgänge definiert werden, die vom Dienst auf dem Clientendpunkt aufgerufen werden können.The callback contract is the interface that defines the operations that the service can call on the client endpoint. Ein Duplexvertrag erfordert keine Sitzung, die vom System bereitgestellten Duplexbindungen nutzen allerdings Sitzungen.A duplex contract does not require a session, although the system-provided duplex bindings make use of them.

Das folgende Beispiel zeigt einen Duplexvertrag.The following is an example of a duplex contract.

[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

Die CalculatorService-Klasse implementiert die primäre ICalculatorDuplex-Schnittstelle.The CalculatorService class implements the primary ICalculatorDuplex interface. Der Dienst verwendet den PerSession-Instanzmodus, um die Ergebnisse für die einzelnen Sitzungen zu pflegen.The service uses the PerSession instance mode to maintain the result for each session. Die private Callback-Eigenschaft greift auf den Rückrufkanal zu, der zum Client führt.A private property named Callback accesses the callback channel to the client. Der Dienst nutzt den Rückruf, um über die Rückrufschnittstelle Nachrichten zurück an den Client zu senden, wie im folgenden Beispielcode gezeigt.The service uses the callback for sending messages back to the client through the callback interface, as shown in the following sample code.


[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

Damit Nachrichten vom Dienst empfangen werden können, muss der Client eine Klasse bereitstellen, die die Rückrufschnittstelle des Duplexvertrags implementiert.The client must provide a class that implements the callback interface of the duplex contract, for receiving messages from the service. Der folgende Beispielcode enthält eine CallbackHandler-Klasse, durch die die ICalculatorDuplexCallback-Schnittstelle implementiert wird.The following sample code shows a CallbackHandler class that implements the ICalculatorDuplexCallback interface.

public class CallbackHandler : ICalculatorDuplexCallback
{
    public void Equals(double result)
    {
        Console.WriteLine("Equals({0})", result);
    }

    public void Equation(string eqn)
    {
        Console.WriteLine("Equation({0})", 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

Der WCF-Client, der generiert wird, für die ein Duplexvertrag erfordert eine InstanceContext Klasse, um bei der Erstellung bereitgestellt werden.The WCF client that is generated for a duplex contract requires a InstanceContext class to be provided upon construction. Diese InstanceContext-Klasse wird als Standort für ein Objekt verwendet, das die Rückrufschnittstelle implementiert und die vom Dienst zurückgesendeten Nachrichten verarbeitet.This InstanceContext class is used as the site for an object that implements the callback interface and handles messages that are sent back from the service. Eine InstanceContext-Klasse wird mit einer Instanz der CallbackHandler-Klasse erstellt.An InstanceContext class is constructed with an instance of the CallbackHandler class. Dieses Objekt verarbeitet die vom Dienst über die Rückrufschnittstelle an den Client gesendeten Nachrichten.This object handles messages sent from the service to the client on the callback interface.

// 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)

Der Dienst muss so konfiguriert werden, dass eine Bindung bereitgestellt wird, die sowohl eine Sitzungskommunikation als auch eine Duplexkommunikation unterstützt.The configuration for the service must be set up to provide a binding that supports both session communication and duplex communication. Das wsDualHttpBinding-Element unterstützt die sitzungsbasierte Kommunikation und ermöglicht durch Bereitstellung dualer HTTP-Verbindungen (eine Verbindung pro Richtung) auch eine Duplexkommunikation.The wsDualHttpBinding element supports session communication and allows duplex communication by providing dual HTTP connections, one for each direction.

Auf dem Client muss, wie in der folgenden Beispielkonfiguration zu sehen, eine Adresse konfiguriert werden, über die der Server eine Verbindung mit dem Client herstellen kann.On the client, you must configure an address that the server can use to connect to the client, as shown in the following sample configuration.

Hinweis

Nichtduplex-Clients, bei denen keine Authentifizierung über eine sichere Konversation möglich ist, lösen in der Regel eine MessageSecurityException aus.Non-duplex clients that fail to authenticate using a secure conversation typically throw a MessageSecurityException. Wenn jedoch bei einem Duplexclient, der eine sichere Konversation verwendet, keine Authentifizierung möglich ist, erhält der Client stattdessen eine TimeoutException.However, if a duplex client that uses a secure conversation fails to authenticate, the client receives a TimeoutException instead.

Wenn Sie mit dem WSHttpBinding-Element einen Client/Dienst erstellen und keinen Clientrückrufendpunkt aufnehmen, wird der folgende Fehler ausgegeben:If you create a client/service using the WSHttpBinding element and you do not include the client callback endpoint, you will receive the following error.

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

Der folgende Beispielcode zeigt, wie an den Client Endpunktadresse programmgesteuert.The following sample code shows how to specify the client endpoint address programmatically.

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/")  

Der folgende Beispielcode zeigt, wie Sie die Clientendpunktadresse in der Konfiguration angeben können:The following sample code shows how to specify the client endpoint address in configuration.

<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

Das Schließen des zugehörigen Kanals durch einen Dienst oder Client wird vom Duplexmodell nicht in jedem Fall automatisch erkannt.The duplex model does not automatically detect when a service or client closes its channel. Wenn ein Client unerwartet beendet wird, wird der Dienst daher (standardmäßig) nicht benachrichtigt.So if a client unexpectedly terminates, by default the service will not be notified, or if a client unexpectedly terminates, the service will not be notified. Clients und Dienste können eigene Protokolle implementieren, um sich bei Bedarf wechselseitig zu benachrichtigen.Clients and services can implement their own protocol to notify each other if they so choose.

Siehe auchSee Also

DuplexDuplex
Angeben des ClientlaufzeitverhaltensSpecifying Client Run-Time Behavior
Vorgehensweise: Erstellen einer Kanalfactory, mit der ein Kanal erstellt und verwaltet werden kannHow to: Create a Channel Factory and Use it to Create and Manage Channels