Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Un contrat de service duplex est un modèle d’échange de messages dans lequel les deux points de terminaison peuvent envoyer des messages à l’autre indépendamment. Par conséquent, un service duplex peut retransmettre des messages au point de terminaison client, offrant un comportement similaire à un événement. La communication duplex se produit lorsqu’un client se connecte à un service et fournit au service un canal sur lequel le service peut renvoyer des messages au client. Notez que le comportement de type événement des services duplex fonctionne uniquement dans une session.
Pour créer un contrat duplex, vous créez une paire d’interfaces. La première est l’interface de contrat de service qui décrit les opérations qu’un client peut appeler. Ce contrat de service doit spécifier un contrat de rappel dans la ServiceContractAttribute.CallbackContract propriété. Le contrat de rappel est l’interface qui définit les opérations que le service peut appeler sur le point de terminaison client. Un contrat duplex ne requiert pas de session, bien que les liaisons duplex fournies par le système en utilisent.
Voici un exemple de contrat duplex.
[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
La CalculatorService
classe implémente l’interface principale ICalculatorDuplex
. Le service utilise le mode d’instance PerSession pour conserver le résultat de chaque session. Une propriété privée appelée Callback
accède au canal de rappel au client. Le service utilise le rappel pour renvoyer des messages au client via l’interface de rappel, comme indiqué dans l’exemple de code suivant.
[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
Le client doit fournir une classe qui implémente l’interface de rappel du contrat duplex, pour recevoir des messages du service. L’exemple de code suivant montre une CallbackHandler
classe qui implémente l’interface ICalculatorDuplexCallback
.
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
Le client WCF généré pour un contrat duplex nécessite qu’une InstanceContext classe soit fournie lors de la construction. Cette InstanceContext classe est utilisée comme site pour un objet qui implémente l’interface de rappel et gère les messages renvoyés par le service. Une InstanceContext classe est construite avec une instance de la CallbackHandler
classe. Cet objet gère les messages envoyés du service au client sur l’interface de rappel.
// 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)
La configuration du service doit être configurée pour fournir une liaison qui prend en charge à la fois la communication de session et la communication duplex. L’élément prend en charge la wsDualHttpBinding
communication de session et autorise la communication duplex en fournissant des connexions HTTP doubles, une pour chaque direction.
Sur le client, vous devez configurer une adresse que le serveur peut utiliser pour se connecter au client, comme indiqué dans l’exemple de configuration suivant.
Remarque
Les clients non duplex qui ne parviennent pas à s'authentifier à l'aide d'une conversation sécurisée lèvent en général une exception MessageSecurityException. Toutefois, si un client duplex qui utilise une conversation sécurisée ne parvient pas à s’authentifier, il reçoit un TimeoutException à la place.
Si vous créez un client/service à l’aide de l’élément WSHttpBinding
et que vous n’incluez pas le point de terminaison de rappel du client, vous recevrez l’erreur suivante.
HTTP could not register URL
htp://+:80/Temporary_Listen_Addresses/<guid> because TCP port 80 is being used by another application.
L’exemple de code suivant montre comment spécifier l’adresse du point de terminaison client par programmation.
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/")
L’exemple de code suivant montre comment spécifier l’adresse du point de terminaison client dans la 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>
Avertissement
Le modèle duplex ne détecte pas automatiquement lorsqu’un service ou un client ferme son canal. Par conséquent, si un client se termine de façon inattendue, par défaut, le service ne sera pas averti ou si un service se termine de façon inattendue, le client ne sera pas averti. Si vous utilisez un service déconnecté, l’exception CommunicationException est levée. Les clients et les services peuvent implémenter leur propre protocole pour les avertir les uns des autres s’ils le choisissent. Pour plus d’informations sur la gestion des erreurs, consultez gestion des erreurs WCF.