Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Um contrato de serviço duplex é um padrão de troca de mensagens no qual ambos os extremos podem enviar mensagens para o outro, de forma independente. Um serviço duplex, portanto, pode enviar mensagens de volta para o ponto de extremidade do cliente, fornecendo comportamento semelhante a um evento. A comunicação duplex ocorre quando um cliente se conecta a um serviço e fornece ao serviço um canal no qual o serviço pode enviar mensagens de volta ao cliente. Observe que o comportamento semelhante a um evento dos serviços duplex só funciona dentro de uma sessão.
Para criar um contrato duplex, crie um par de interfaces. A primeira é a interface do contrato de serviço que descreve as operações que um cliente pode invocar. Esse contrato de serviço deve especificar um contrato de callback na propriedade ServiceContractAttribute.CallbackContract. O contrato de callback é a interface que define as operações que o serviço pode chamar no endpoint do cliente. Um contrato duplex não requer uma sessão, embora as ligações duplex fornecidas pelo sistema façam uso delas.
Segue-se um exemplo de um contrato 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
A CalculatorService classe implementa a interface primária ICalculatorDuplex . O serviço usa o PerSession modo de instância para manter o resultado de cada sessão. Uma propriedade privada chamada Callback acede ao canal de retorno de chamada para o cliente. O serviço usa o retorno de chamada para enviar mensagens de volta ao cliente por meio da interface de retorno de chamada, conforme mostrado no código de exemplo a seguir.
[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
O cliente deve fornecer uma classe que implemente a interface de retorno de chamada do contrato duplex, para receber mensagens do serviço. O código de exemplo a seguir mostra uma CallbackHandler classe que implementa a ICalculatorDuplexCallback interface.
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
O cliente WCF que é gerado para um contrato duplex requer uma InstanceContext classe a ser fornecida durante a construção. Essa InstanceContext classe é usada como o site para um objeto que implementa a interface de retorno de chamada e manipula mensagens que são enviadas de volta do serviço. Uma InstanceContext classe é construída com uma instância da CallbackHandler classe. Este objeto processa mensagens enviadas do serviço para o cliente na interface de 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)
A configuração do serviço deve ser feita para fornecer uma vinculação que suporte tanto a comunicação de sessão quanto a comunicação duplex. O wsDualHttpBinding elemento suporta comunicação de sessão e permite comunicação duplex fornecendo conexões HTTP duplas, uma para cada direção.
No cliente, você deve configurar um endereço que o servidor pode usar para se conectar ao cliente, conforme mostrado na configuração de exemplo a seguir.
Observação
Os clientes não duplex que não conseguem autenticar usando uma comunicação segura normalmente lançam uma exceção MessageSecurityException. No entanto, se um cliente duplex que usa uma conversa segura não conseguir autenticar, o cliente receberá um TimeoutException em vez disso.
Se você criar um cliente/serviço usando o WSHttpBinding elemento e não incluir o ponto de extremidade de retorno de chamada do cliente, receberá o seguinte erro.
HTTP could not register URL
htp://+:80/Temporary_Listen_Addresses/<guid> because TCP port 80 is being used by another application.
O código de exemplo a seguir mostra como especificar o endereço do ponto de extremidade do cliente programaticamente.
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/")
O código de exemplo a seguir mostra como especificar o endereço do ponto de extremidade do cliente na configuração.
<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>
Advertência
O modelo duplex não deteta automaticamente quando um serviço ou cliente fecha seu canal. Portanto, se um cliente encerrar inesperadamente, por padrão, o serviço não será notificado, ou se um serviço for encerrado inesperadamente, o cliente não será notificado. Se você usar um serviço desconectado, a CommunicationException exceção será gerada. Clientes e serviços podem implementar seu próprio protocolo para notificar uns aos outros, se assim desejarem. Para obter mais informações sobre tratamento de erros, consulte Tratamento de erros WCF.