Duplexní služby
Duplexní kontrakt služby je vzor výměny zpráv, ve kterém oba koncové body mohou posílat zprávy druhému nezávisle. Duplexní služba proto může posílat zprávy zpět do koncového bodu klienta a poskytovat chování podobné událostem. Duplexní komunikace nastane, když se klient připojí ke službě a poskytne službě kanál, na kterém může služba odesílat zprávy zpět klientovi. Všimněte si, že chování duplexních služeb podobné události funguje pouze v rámci relace.
Pokud chcete vytvořit duplexní kontrakt, vytvoříte dvojici rozhraní. První je rozhraní kontraktu služby, které popisuje operace, které může klient vyvolat. Tento kontrakt služby musí ve vlastnosti zadat kontrakt zpětného ServiceContractAttribute.CallbackContract volání. Kontrakt zpětného volání je rozhraní, které definuje operace, které může služba volat na koncový bod klienta. Duplexní kontrakt nevyžaduje relaci, i když systémové duplexní vazby využívají.
Následuje příklad duplexního kontraktu.
[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
Třída CalculatorService
implementuje primární ICalculatorDuplex
rozhraní. Služba používá PerSession režim instance k zachování výsledku pro každou relaci. Privátní vlastnost s názvem Callback
přistupuje ke kanálu zpětného volání klientovi. Služba používá zpětné volání pro odesílání zpráv zpět klientovi prostřednictvím rozhraní zpětného volání, jak je znázorněno v následujícím vzorovém kódu.
[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
Klient musí poskytnout třídu, která implementuje rozhraní zpětného volání duplexního kontraktu pro příjem zpráv ze služby. Následující ukázkový kód ukazuje CallbackHandler
třídu, která implementuje ICalculatorDuplexCallback
rozhraní.
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
Klient WCF vygenerovaný pro duplexní kontrakt vyžaduje, aby byla při sestavování poskytována InstanceContext třída. Tato InstanceContext třída se používá jako lokalita pro objekt, který implementuje rozhraní zpětného volání a zpracovává zprávy odeslané zpět ze služby. Třída InstanceContext je vytvořena s instancí CallbackHandler
třídy. Tento objekt zpracovává zprávy odeslané ze služby klientovi v rozhraní zpětného volání.
// 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)
Konfigurace služby musí být nastavená tak, aby poskytovala vazbu, která podporuje komunikaci relace i duplexní komunikaci. Element wsDualHttpBinding
podporuje komunikaci relace a umožňuje duplexní komunikaci tím, že poskytuje duální připojení HTTP, jednu pro každý směr.
V klientovi musíte nakonfigurovat adresu, kterou server může použít pro připojení k klientovi, jak je znázorněno v následující ukázkové konfiguraci.
Poznámka:
Ne duplexní klienti, kteří se nepodaří ověřit pomocí zabezpečené konverzace, obvykle vyvolá MessageSecurityExceptionchybu . Pokud se ale oboustranný klient, který používá zabezpečenou konverzaci, nepodaří ověřit, klient místo toho obdrží TimeoutException .
Pokud vytvoříte klienta nebo službu pomocí elementu WSHttpBinding
a nezahrnete koncový bod zpětného volání klienta, zobrazí se následující chyba.
HTTP could not register URL
htp://+:80/Temporary_Listen_Addresses/<guid> because TCP port 80 is being used by another application.
Následující ukázkový kód ukazuje, jak programově zadat adresu koncového bodu klienta.
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/")
Následující ukázkový kód ukazuje, jak zadat adresu koncového bodu klienta v konfiguraci.
<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>
Upozorňující
Duplexní model automaticky nezjistí, kdy služba nebo klient zavře svůj kanál. Takže pokud se klient neočekávaně ukončí, služba ve výchozím nastavení nebude upozorněna nebo pokud se služba neočekávaně ukončí, klient nebude upozorněn. Pokud používáte službu, která je odpojena, je CommunicationException vyvolána výjimka. Klienti a služby můžou implementovat svůj vlastní protokol, aby se navzájem informovali, pokud tak zvolí. Další informace o zpracování chyb naleznete v tématu Zpracování chyb WCF.