Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Un contratto di servizio duplex è un modello di scambio di messaggi in cui entrambi gli endpoint possono inviare messaggi all'altro in modo indipendente. Un servizio duplex, pertanto, può inviare messaggi all'endpoint client, con un comportamento simile a quello di un evento. La comunicazione duplex si verifica quando un client si connette a un servizio e fornisce al servizio un canale in cui il servizio può inviare messaggi al client. Si noti che il comportamento tipo evento dei servizi duplex funziona solo durante una sessione.
Per creare un contratto duplex, si crea una coppia di interfacce. Il primo è l'interfaccia del contratto di servizio che descrive le operazioni che un client può richiamare. Tale contratto di servizio deve specificare un contratto di callback nella ServiceContractAttribute.CallbackContract proprietà . Il contratto di callback è l'interfaccia che definisce le operazioni che il servizio può chiamare sull'endpoint client. Un contratto duplex non richiede una sessione, anche se le associazioni duplex fornite dal sistema ne fanno uso.
Di seguito è riportato un esempio di contratto 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 implementa l'interfaccia primaria ICalculatorDuplex
. Il servizio utilizza la modalità istanza PerSession per mantenere il risultato di ogni sessione. Una proprietà privata chiamata Callback
accede al client tramite il canale di callback. Il servizio usa il callback per l'invio di messaggi al client tramite l'interfaccia di callback, come illustrato nel codice di esempio seguente.
[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
Il client deve fornire una classe che implementa l'interfaccia di callback del contratto duplex per la ricezione di messaggi dal servizio. Il codice di esempio seguente illustra una CallbackHandler
classe che implementa l'interfaccia 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
La classe InstanceContext deve essere fornita durante la costruzione di un client WCF generato per un contratto duplex. Questa InstanceContext classe viene utilizzata come sito per un oggetto che implementa l'interfaccia di callback e gestisce i messaggi inviati dal servizio. Una InstanceContext classe viene costruita con un'istanza della CallbackHandler
classe . Questo oggetto gestisce i messaggi inviati dal servizio al client nell'interfaccia di callback.
// 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 configurazione per il servizio deve essere configurata per fornire un'associazione che supporta la comunicazione di sessione e la comunicazione duplex. L'elemento wsDualHttpBinding
supporta la comunicazione di sessione e consente la comunicazione duplex fornendo connessioni HTTP doppie, una per ogni direzione.
Nel client è necessario configurare un indirizzo che il server può usare per connettersi al client, come illustrato nella configurazione di esempio seguente.
Annotazioni
I client non duplex che non riescono a eseguire l'autenticazione utilizzando una conversazione sicura di solito generano un'eccezione MessageSecurityException. Tuttavia, se un client duplex che utilizza una conversazione sicura fallisce nell'autenticazione, il client riceve invece TimeoutException.
Se si crea un client/servizio usando l'elemento WSHttpBinding
e non si include l'endpoint di callback client, verrà visualizzato l'errore seguente.
HTTP could not register URL
htp://+:80/Temporary_Listen_Addresses/<guid> because TCP port 80 is being used by another application.
Il codice di esempio seguente illustra come specificare l'indirizzo dell'endpoint client a livello di codice.
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/")
Il codice di esempio seguente illustra come specificare l'indirizzo dell'endpoint client nella configurazione.
<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>
Avvertimento
Il modello duplex non rileva automaticamente quando un servizio o un client chiude il canale. Pertanto, se un client termina in modo imprevisto, per impostazione predefinita il servizio non riceverà alcuna notifica o se un servizio termina in modo imprevisto, il client non riceverà alcuna notifica. Se si usa un servizio disconnesso, viene generata l'eccezione CommunicationException . I client e i servizi possono implementare il proprio protocollo per notificarsi tra loro, se lo scelgono. Per altre informazioni sulla gestione degli errori, vedere Gestione degli errori WCF.