Kétoldalas szolgáltatások
A kétoldalas szolgáltatási szerződés olyan üzenetcsere-minta, amelyben mindkét végpont egymástól függetlenül küldhet üzeneteket a másiknak. A kétoldalas szolgáltatások ezért vissza tudnak küldeni üzeneteket az ügyfélvégpontra, így eseményszerű működést biztosítanak. Kétoldalas kommunikáció akkor fordul elő, ha egy ügyfél csatlakozik egy szolgáltatáshoz, és olyan csatornát biztosít a szolgáltatásnak, amelyen a szolgáltatás üzeneteket küldhet vissza az ügyfélnek. Vegye figyelembe, hogy a kétoldalas szolgáltatások eseményszerű viselkedése csak egy munkameneten belül működik.
Kétoldalas szerződés létrehozásához létre kell hoznia egy pár interfészt. Az első a szolgáltatási szerződés felülete, amely leírja az ügyfél által meghívható műveleteket. A szolgáltatási szerződésnek meg kell adnia egy visszahívási szerződést a ServiceContractAttribute.CallbackContract tulajdonságban. A visszahívási szerződés az a felület, amely meghatározza azokat a műveleteket, amelyeket a szolgáltatás meghívhat az ügyfélvégponton. A kétoldalas szerződések nem igényelnek munkamenetet, bár a rendszer által biztosított kétoldalas kötések használják őket.
Az alábbi példa kétoldalas szerződésre mutat be példát.
[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
Az CalculatorService
osztály implementálja az elsődleges ICalculatorDuplex
felületet. A szolgáltatás a PerSession példánymódot használja az egyes munkamenetek eredményének fenntartásához. A névvel ellátott Callback
magántulajdonság hozzáfér a visszahívási csatornához az ügyfélhez. A szolgáltatás a visszahívás használatával küldi vissza az üzeneteket az ügyfélnek a visszahívási felületen keresztül, ahogyan az az alábbi mintakódban látható.
[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
Az ügyfélnek meg kell adnia egy osztályt, amely megvalósítja a kétoldalas szerződés visszahívási felületét a szolgáltatástól érkező üzenetek fogadásához. Az alábbi mintakód egy olyan osztályt CallbackHandler
mutat be, amely implementálja az interfészt ICalculatorDuplexCallback
.
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
A kétoldalas szerződéshez létrehozott WCF-ügyfélnek az építéskor meg kell adni egy InstanceContext osztályt. Ez InstanceContext az osztály egy olyan objektum webhelye, amely megvalósítja a visszahívási felületet, és kezeli a szolgáltatásból visszaküldött üzeneteket. Az InstanceContext osztály az osztály egy példányával CallbackHandler
jön létre. Ez az objektum kezeli a szolgáltatásból az ügyfélnek a visszahívási felületen küldött üzeneteket.
// 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 szolgáltatás konfigurációját úgy kell beállítani, hogy olyan kötést biztosítson, amely támogatja a munkamenet-kommunikációt és a kétoldalas kommunikációt is. Az wsDualHttpBinding
elem támogatja a munkamenet-kommunikációt, és lehetővé teszi a kétirányú kommunikációt kettős HTTP-kapcsolatok biztosításával, amelyek mindegyik irányban egy-egyhez csatlakoznak.
Az ügyfélen konfigurálnia kell egy címet, amelyet a kiszolgáló az ügyfélhez való csatlakozáshoz használhat az alábbi mintakonfigurációban látható módon.
Feljegyzés
Azok a nem kétoldalas ügyfelek, amelyek nem hitelesíthetők biztonságos beszélgetéssel, általában egy MessageSecurityException. Ha azonban egy biztonságos beszélgetést használó kétoldalas ügyfél hitelesítése sikertelen, az ügyfél ehelyett kap egy ilyen ügyfelet TimeoutException .
Ha az WSHttpBinding
elemet használva hoz létre egy ügyfelet/szolgáltatást, és nem tartalmazza az ügyfélvisszahívási végpontot, a következő hibaüzenet jelenik meg.
HTTP could not register URL
htp://+:80/Temporary_Listen_Addresses/<guid> because TCP port 80 is being used by another application.
Az alábbi mintakód bemutatja, hogyan adhatja meg az ügyfélvégpont címét programozott módon.
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/")
Az alábbi mintakód bemutatja, hogyan adhatja meg az ügyfélvégpont címét a konfigurációban.
<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>
Figyelmeztetés
A kétoldalas modell nem észleli automatikusan, ha egy szolgáltatás vagy ügyfél bezárja a csatornáját. Így ha egy ügyfél váratlanul leáll, alapértelmezés szerint a szolgáltatás nem fog értesítést kapni, vagy ha egy szolgáltatás váratlanul leáll, az ügyfél nem fog értesítést kapni. Ha leválasztott szolgáltatást használ, a CommunicationException rendszer kivételt emel ki. Az ügyfelek és a szolgáltatások saját protokollt alkalmazhatnak, hogy értesítsék egymást, ha úgy döntenek. A hibakezeléssel kapcsolatos további információkért lásd: WCF hibakezelés.