Frage

Ich versuche, eine SOA zu bauen, wo Kunden lange laufende Abfragen auf dem Server durchführen können und der Server antwortet einen Rückruf verwendet wird.

Ich möchte in der Lage sein, wenn der Client die Verbindung trennt (durch Benutzer initiiert Herunterfahren, nicht behandelte Ausnahme oder Verlust der Netzwerkverbindung) zu erfassen, so dass der Server wählen können, die teure Anforderung abzubrechen.

Ich bin eine Vielzahl von Fehlerfällen zu testen, aber ich kann nicht sicher Event-Handler scheinen, zu schießen.

Getestet Fehlerfälle: Abtöten der Client-Prozess nach der Anforderung. ein Programm wie CurrPorts mit der 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 die zugrunde liegende TCP-Verbindung zu verwenden, um der Lage sein, einige dieser Dinge zu erkennen.

War es hilfreich?

Lösung

In seinem "Programming WCF Services Buch, Juval Lowy erklärt, dass WCF bietet keine mechansim für Service Rückrufe Verwaltung, und dies muss explizit durch den Service und Client verwaltet werden. Wenn der Dienst versucht, einen Rückruf anzurufen, die auf dem Client geschlossen wurden, wird ein ObjectDisposedException auf dem Dienstkanal geworfen werden.

Er empfiehlt eine Connect und Disconnect-Methode auf den Servicevertrag Zugabe - da muss der Rückruf an den Service zur Verfügung gestellt werden, wenn diese aufgerufen werden, kann die Service-Client-Rückrufe verwalten. Es liegt dann an den Client, um sicherzustellen, dass es Disconnect aufruft, wenn es nicht mehr für Rückrufe aus dem Dienst zu empfangen, und der Service müssen alle Ausnahmen behandeln, wenn Rückrufe an den Client aufgerufen wird.

Andere Tipps

versuchen, dies zu überprüfen, ob das Rückrufobjekt noch gültig ist:

(((ICommunicationObject)myCallbackObject).State == CommunicationState.Opened)

myCallbackObject in diesem Fall ist das Objekt, durch die Sie den Rückruf durchführen können, das heißt, die man den Rückrufvertrag Umsetzung

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top