سؤال

وأنا أحاول لبناء الخدمية حيث يمكن للعملاء تنفيذ استعلامات طويلة قيد التشغيل على الخادم والخادم يستجيب باستخدام الاستدعاء.

وأود أن تكون قادرة على الكشف عن حالة قطع اتصال العميل (من خلال المستخدم بدأ الاغلاق، واستثناء غير معالج أو فقدان الاتصال بالشبكة) حتى أن الخادم يمكن أن تختار لإلغاء الطلب مكلفة.

وأنا على اختبار مجموعة متنوعة من الحالات الفشل، ولكن أنا لا يمكن أن يبدو للحصول على بعض معالجات الأحداث لاطلاق النار.

وحالات الفشل اختبار: قتل عملية عميل بعد الطلب. باستخدام برنامج مثل 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 الأساسي للكشف عن بعض من هذه الأمور.

هل كانت مفيدة؟

المحلول

في بلدة 'البرمجة WCF الخدمات "الكتاب، يشرح جوفال لووي أن WCF لا يوفر mechansim لإدارة الاسترجاعات الخدمة، وهذا يجب أن تدار من قبل الخدمة والعميل صراحة. إذا تحاول الخدمة استدعاء الاستدعاء الذي كان مغلقا على العميل، سيتم إلقاء ObjectDisposedException على قناة الخدمة.

وويوصي بإضافة أسلوب الاتصال وقطع الاتصال لعقد الخدمة - منذ يجب تقديم الاستدعاء للخدمة عندما يتم استدعاء هذه، يمكن للخدمة إدارة الاسترجاعات العميل. ومن ثم تصل إلى العميل للتأكد من أنه يدعو قطع الاتصال عند أنه لم يعد يرغب في تلقي رد من الخدمة، والخدمة يجب التعامل مع أي استثناءات عند استدعاء الاستدعاء إلى العميل.

نصائح أخرى

وهذه محاولة لمعرفة ما اذا كان الكائن الاستدعاء لا يزال قائما:

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

وmyCallbackObject في هذه الحالة هو الكائن الذي يمكنك من خلال إجراء الاستدعاء، أي واحد تنفيذ العقد رد

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top