문제

클라이언트가 서버에서 장기 실행 쿼리를 수행할 수 있고 서버가 콜백을 사용하여 응답하는 SOA를 구축하려고 합니다.

서버가 비용이 많이 드는 요청을 취소하도록 선택할 수 있도록 클라이언트 연결이 끊어졌는지(사용자가 시작한 종료, 처리되지 않은 예외 또는 네트워크 연결 끊김 등을 통해) 감지할 수 있기를 원합니다.

다양한 실패 사례를 테스트하고 있지만 특정 이벤트 핸들러가 실행되지 않는 것 같습니다.

테스트된 실패 사례:요청 후 클라이언트 프로세스를 종료합니다.CurrPorts와 같은 프로그램을 사용하여 TCP 연결을 닫습니다.

테스트 코드:

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);
        }
    }
}

이러한 종류의 실패 사례를 처리하는 가장 좋은 방법은 무엇입니까?나는 이러한 것들을 감지하기 위해 기본 TCP 연결을 사용할 수 있기를 원합니다.

도움이 되었습니까?

해결책

Juval Lowy는 'WCF 서비스 프로그래밍' 책에서 WCF가 서비스 콜백 관리를 위한 메커니즘을 제공하지 않으며 이는 서비스와 클라이언트에서 명시적으로 관리해야 한다고 설명합니다.서비스가 클라이언트에서 닫힌 콜백을 호출하려고 시도하면 서비스 채널에서 ObjectDisposedException이 발생합니다.

그는 서비스 계약에 Connect 및 Disconnect 메서드를 추가할 것을 권장합니다. 콜백이 호출될 때 서비스에 콜백을 제공해야 하기 때문에 서비스는 클라이언트 콜백을 관리할 수 있습니다.더 이상 서비스로부터 콜백을 수신하지 않으려는 경우 Disconnect를 호출하는 것은 클라이언트의 몫이며 서비스는 클라이언트에 대한 콜백을 호출할 때 모든 예외를 처리해야 합니다.

다른 팁

콜백 객체가 여전히 유효한지 확인하려면 이것을 시도하십시오.

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

이 경우 MyCallbackObject 콜백을 수행 할 수있는 객체, 즉 콜백 계약을 구현하는 객체입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top