Ich versuche, eine SOA zu erstellen, bei der Clients lange laufende Abfragen auf dem Server ausführen können und der Server mit einem Rückruf reagiert.Erkennen von Client-Death in WCF-Duplex-Verträgen
Ich möchte in der Lage zu erkennen, wenn der Client die Verbindung trennt (durch Benutzer initiiert Herunterfahren, unbehandelt Ausnahme oder Verlust der Netzwerkverbindung), so dass der Server die teure Anfrage abbrechen kann.
Ich teste eine Vielzahl von Fehlerfällen, aber ich kann nicht scheinen bestimmte Ereignishandler zu feuern.
Geprüfte Fehlerfälle: Töten des Client-Prozesses Nach der Anfrage. Verwenden Sie ein Programm wie CurrPorts, um die TCP-Verbindung zu schließen.
Testcode:
using System;
using System.ServiceModel;
using System.Threading;
namespace WCFICommunicationObjectExperiments
{
class Program
{
static void Main(string[] args)
{
var binding = new NetTcpBinding(SecurityMode.None);
var serviceHost = new ServiceHost(typeof (Server));
serviceHost.AddServiceEndpoint(typeof (IServer), binding, "net.tcp://localhost:5000/Server");
serviceHost.Open();
Console.WriteLine("Host is running, press <ENTER> to exit.");
Console.ReadLine();
}
}
[ServiceContract(CallbackContract = typeof(IClient))]
public interface IServer
{
[OperationContract]
void StartProcessing(string Query);
}
public interface IClient
{
[OperationContract]
void RecieveResults(string Results);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Server : IServer
{
public void StartProcessing(string Query)
{
Thread.Sleep(5000);
//Callback Channel
var clientCallback = OperationContext.Current.GetCallbackChannel<IClient>();
var clientCallbackCommunicationObject = ((ICommunicationObject) clientCallback);
EventHandler faultedHandlerCallback = (o, s) => Console.WriteLine("Client Channel Faulted.");
EventHandler closedHandlerCallback = (o, s) => Console.WriteLine("Client Channel Closed.");
clientCallbackCommunicationObject.Faulted += faultedHandlerCallback;
clientCallbackCommunicationObject.Closed += closedHandlerCallback;
//Request Channel
var requestChannel = OperationContext.Current.Channel;
EventHandler faultedHandlerRequest = (o, s) => Console.WriteLine("Request Channel Faulted.");
EventHandler closedHandlerRequest = (o, s) => Console.WriteLine("Request Channel Closed.");
requestChannel.Faulted += faultedHandlerRequest;
requestChannel.Closed += closedHandlerRequest;
try
{
clientCallback.RecieveResults("42.");
}
catch (CommunicationObjectAbortedException ex)
{
Console.WriteLine("Client Aborted the connection");
}
catch (CommunicationObjectFaultedException ex)
{
Console.WriteLine("Client Died.");
}
clientCallbackCommunicationObject.Faulted -= faultedHandlerCallback;
clientCallbackCommunicationObject.Faulted -= closedHandlerCallback;
requestChannel.Faulted -= faultedHandlerRequest;
requestChannel.Closed -= closedHandlerRequest;
}
}
public class ClientToTestStates : IClient
{
private IServer m_Server;
private readonly ManualResetEvent m_ReceivedEvent = new ManualResetEvent(false);
private readonly ManualResetEvent m_ChannelFaulted = new ManualResetEvent(false);
private readonly ManualResetEvent m_ChannelClosed = new ManualResetEvent(false);
public ClientToTestStates()
{
var binding = new NetTcpBinding(SecurityMode.None);
var channelFactory = new DuplexChannelFactory<IServer>(this, binding, new EndpointAddress("net.tcp://localhost:5000/Server"));
m_Server = channelFactory.CreateChannel();
((ICommunicationObject)m_Server).Open();
((ICommunicationObject)m_Server).Faulted += ChannelFaulted;
((ICommunicationObject)m_Server).Closed += ChannelClosed;
m_Server.StartProcessing("What is the answer?");
WaitHandle.WaitAny(new WaitHandle[] {m_ReceivedEvent, m_ChannelFaulted, m_ChannelClosed});
}
void ChannelFaulted(object sender, EventArgs e)
{
m_ChannelFaulted.Set();
Console.WriteLine("Channel Faulted.");
}
void ChannelClosed(object sender, EventArgs e)
{
m_ChannelClosed.Set();
Console.WriteLine("Channel Closed.");
}
public void RecieveResults(string results)
{
m_ReceivedEvent.Set();
Console.WriteLine("Recieved Results {0}", results);
}
}
}
Was ist die beste Praxis, diese Art von Fehlerfällen zu behandeln? Ich möchte in der Lage sein, die zugrunde liegende TCP-Verbindung zu verwenden, um einige dieser Dinge zu erkennen.
Sie haben versuchte, Zuverlässigkeit zu aktivieren? TCP bietet Punkt-zu-Punkt-Zuverlässigkeit.
Nachrichtenzuverlässigkeit (über WS-Zuverlässigkeit) bietet durchgängige Zuverlässigkeit.
Und im Gegenzug glaube ich, dass Sie benachrichtigt werden, wenn eine Seite "ohne weiteres" weggeht. Für Transporte, die dies unterstützen, ist es die beste Vorgehensweise, die Zuverlässigkeit immer zu aktivieren, obwohl einige Netzwerke "Goo" sie möglicherweise nicht unterstützen. –