Sto provando a creare un SOA in cui i client possono eseguire query a esecuzione prolungata sul server e il server risponde utilizzando una richiamata.Determinazione del decesso del client nei contratti duplex WCF
Mi piacerebbe essere in grado di rilevare se il client si disconnette (attraverso l'arresto avviato dall'utente, un'eccezione non gestita o la perdita della connettività di rete) in modo che il server possa scegliere di annullare la richiesta costosa.
Sto testando una serie di casi di errore, ma non riesco a convincere alcuni gestori di eventi a sparare.
Casi di errore verificati: Uccisione del processo client Dopo la richiesta. Utilizzo di un programma come CurrPorts per chiudere la connessione TCP.
Codice di prova:
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);
}
}
}
Qual è la prassi migliore per gestire questo tipo di casi di insufficienza? Mi piacerebbe essere in grado di utilizzare la connessione TCP sottostante per rilevare alcune di queste cose.
Avete provato ad accendere Affidabilità? TCP fornisce affidabilità point-to-point.
L'affidabilità dei messaggi (tramite WS-Reliability) garantisce l'affidabilità end-to-end.
E a sua volta credo che ti informeremo quando entrambe le parti "se ne andranno" senza tanti complimenti. Per i trasporti che lo supportano, è consigliabile attivare sempre l'affidabilità, anche se alcuni "goo" di rete potrebbero non supportarlo. –