Pergunta

Eu estou tentando construir uma SOA, onde os clientes podem executar longo executar consultas no servidor e as responde servidor usando uma chamada de retorno.

Eu gostaria de ser capaz de detectar se o cliente se desconecta (através iniciado pelo usuário desligamento, exceção ou perda de conectividade de rede sem tratamento) para que o servidor pode optar por cancelar o pedido caro.

Eu estou testando uma variedade de casos de falha, mas eu não consigo obter certos manipuladores de eventos para o fogo.

casos de falha testados: Matar o processo do cliente Após o pedido. Usando um programa como CurrPorts para fechar a conexão TCP.

Test Code:

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 é a melhor prática para lidar com esses tipos de casos de falha? Eu gostaria de ser capaz de usar a conexão TCP subjacente para detectar algumas dessas coisas.

Foi útil?

Solução

Em seu 'Programação serviços WCF' livro, Juval Lowy explica que WCF não fornece uma mechansim para o gerenciamento de chamadas de retorno de serviços, e isso deve ser gerido pelo serviço e cliente explicitamente. Se as tentativas de serviço para invocar um callback que foi fechado no cliente, uma ObjectDisposedException será lançada no canal de serviço.

Ele recomenda a adição de um método de ligar e desligar para o contrato de serviço - uma vez que o retorno de chamada deve ser fornecido para o serviço quando estes são chamados, o serviço pode gerenciar retornos de chamada do cliente. Cabe então ao cliente para garantir que ele chama Desligar quando pretende deixar de receber chamadas de retorno do serviço, eo serviço deve lidar com quaisquer excepções ao invocar chamadas de retorno para o cliente.

Outras dicas

tentar isso para verificar se o objeto de retorno de chamada ainda é válido:

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

myCallbackObject neste caso é o objeto através do qual você pode executar a chamada de retorno, ou seja, a implementação do contrato de retorno de chamada

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top