La détection de Client de la Mort dans WCF Contrats Duplex
Je suis en train de construire une architecture SOA, où les clients peuvent effectuer des requêtes de longue durée sur le serveur et le serveur répond en utilisant une fonction de rappel.
Je voudrais être en mesure de détecter si le client se déconnecte (par l'utilisateur a lancé la fermeture, exception non gérée ou de la perte de connectivité réseau) pour que le serveur peut choisir d'annuler le cher demande.
Je me suis mise à l'essai d'une variété de cas d'insuffisance, mais je n'arrive pas à obtenir certains gestionnaires d'événements à feu.
Testé Cas De:
Tuer les Processus du Client Après la demande.
À l'aide d'un programme comme CurrPorts pour fermer la Connexion TCP.
Code De Test:
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);
}
}
}
Quelle est la meilleure pratique pour gérer ce genre de cas? J'aimerais être en mesure d'utiliser la connexion tcp sous-jacente à détecter certaines de ces choses.
- Avez-vous essayé de retourner sur la Fiabilité? TCP fournit point-à-point de la fiabilité. <br> Message de la fiabilité (via WS-Reliability) fournit de bout en bout de la fiabilité. <br> Et à mon tour, je crois que vous aviserons lorsque l'une des parties ‘disparaît’ sans ménagement. Pour les transports qui le prennent en charge, il est préférable de toujours tourner sur la fiabilité, même si certains le réseau de ‘goo’ ne peut pas le soutenir
Vous devez vous connecter pour publier un commentaire.
Dans sa Programmation des Services WCF livre de Juval Lowy explique que WCF ne fournit pas de mecanisme pour la gestion des rappels de service, et cela doit être géré par le service et le client de manière explicite. Si le service tente d'invoquer un rappel qui a été fermé sur le client, ObjectDisposedException sera jeté sur la voie de service.
Il recommande l'ajout d'une connexion et Déconnexion de la méthode pour le contrat de service - depuis la fonction de rappel doit être fournie au service lorsqu'ils sont appelés, le service peut gérer les rappels de client. Il appartient alors au client de s'assurer qu'il appelle le Débrancher quand il ne souhaite plus recevoir des rappels au service, et le service doit gérer toutes les exceptions lors de l'invocation de rappels pour le client.
essayez ceci pour vérifier si l'objet de rappel est toujours valide:
myCallbackObject dans ce cas est l'objet à travers lequel vous pouvez effectuer le rappel, c'est à dire la mise en œuvre du contrat de rappel