2009-09-15 16 views
28

मैं एक एसओए बनाने की कोशिश कर रहा हूं जहां ग्राहक सर्वर पर लंबे समय से चलने वाले प्रश्न कर सकते हैं और सर्वर कॉलबैक का उपयोग कर जवाब देता है।डब्ल्यूसीएफ डुप्लेक्स अनुबंधों में ग्राहक मौत का पता लगाने

मैं यह पता लगाने में सक्षम होना चाहता हूं कि क्या ग्राहक डिस्कनेक्ट करता है (उपयोगकर्ता द्वारा शुरू किए गए शटडाउन, अनचाहे अपवाद या नेटवर्क कनेक्टिविटी के नुकसान के माध्यम से) ताकि सर्वर महंगा अनुरोध रद्द कर सके।

मैं कई प्रकार के विफलता मामलों का परीक्षण कर रहा हूं लेकिन मुझे कुछ ईवेंट हैंडलर आग लगने लगते हैं।

परीक्षण विफलता मामले: अनुरोध के बाद ग्राहक प्रक्रिया को मारना। टीसीपी कनेक्शन को बंद करने के लिए CurrPorts जैसे प्रोग्राम का उपयोग करना।

टेस्ट कोड:

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

सबसे अच्छा अभ्यास विफलता के मामलों की इन प्रकार संभाल करने के लिए क्या है? मैं इन चीजों में से कुछ का पता लगाने के लिए अंतर्निहित टीसीपी कनेक्शन का उपयोग करने में सक्षम होना चाहता हूं।

+0

आप शामिल हैं को लागू करने यानी विश्वसनीयता पर मोड़ने की कोशिश की? टीसीपी पॉइंट-टू-पॉइंट विश्वसनीयता प्रदान करता है।
संदेश विश्वसनीयता (डब्ल्यूएस-विश्वसनीयता के माध्यम से) अंत तक विश्वसनीयता प्रदान करता है।
और बदले में मेरा मानना ​​है कि आप दोनों को सूचित करेंगे जब दोनों तरफ 'अनजाने में' अनजाने में। इसका समर्थन करने वाले परिवहन के लिए, हमेशा विश्वसनीयता को चालू करना सबसे अच्छा अभ्यास है, हालांकि कुछ नेटवर्क 'goo' इसका समर्थन नहीं कर सकता –

उत्तर

14

अपनी 'प्रोग्रामिंग डब्ल्यूसीएफ सर्विसेज' पुस्तक में, जुवाल लोवी बताते हैं कि डब्ल्यूसीएफ सेवा कॉलबैक के प्रबंधन के लिए मेचांसिम प्रदान नहीं करता है, और इसे सेवा और ग्राहक द्वारा स्पष्ट रूप से प्रबंधित किया जाना चाहिए। अगर सेवा क्लाइंट पर बंद कॉलबैक का आह्वान करने का प्रयास करती है, तो ऑब्जेक्ट डिस्प्ले अपवाद सेवा चैनल पर फेंक दिया जाएगा।

वह सेवा अनुबंध में कनेक्ट और डिस्कनेक्ट विधि जोड़ने की अनुशंसा करता है - चूंकि कॉलबैक को सेवा के लिए प्रदान किया जाना चाहिए, जब सेवा क्लाइंट कॉलबैक प्रबंधित कर सकती है। यह क्लाइंट तक तब तक सुनिश्चित किया जाता है जब यह सेवा से कॉलबैक प्राप्त करने की इच्छा नहीं लेता है, और क्लाइंट को कॉलबैक का आह्वान करते समय सेवा को किसी भी अपवाद को संभालना चाहिए।

+1

जानकारी के लिए धन्यवाद। अप्रत्याशित क्लाइंट विफलता के मामले में जहां कोई डिस्कनेक्ट() को कॉल करने के लिए सर्वर की ओर से उस विफलता का पता लगाने के लिए क्या किया जा सकता है, जो बहुमूल्य संसाधनों को मुक्त करने के लिए किया जा सकता है? – Sindhudweep

+1

ने कहा कि ओएस जानता है कि टीसीपी कनेक्शन को जीवित पैकेट नहीं मिला है। एक डब्ल्यूसीएफ सर्वर के लिए यह जानना संभव होना चाहिए कि ग्राहक चले गए हैं। तो इसके बाद एक बेहतर जवाब होना चाहिए। मुझे नहीं पता कि यह क्या है! –

+0

ओएस टीसीपी कनेक्शन का उपयोग कर सकते हैं। मेरे परीक्षणों में मैं Net.tcp बाध्यकारी का उपयोग कर रहा था और मैं चैनल दोषपूर्ण घटनाएं प्राप्त कर रहा था। दुर्भाग्यवश यदि टीसीपी कनेक्शन एक मशीन के लिए है जो रिले के रूप में कार्य कर रहा है (वैश्विक बाध्यकारी के साथ एसएसएच के रिमोट फ़ॉरवर्डिंग का उपयोग करके) ओएस को टीसीपी कनेक्शन बंद नहीं होता है (क्योंकि रिले मशीन से कनेक्शन वास्तव में बंद नहीं हुआ है)। यह मेरे परीक्षण में मैंने देखा अजीब व्यवहार पैदा कर रहा था। – Sindhudweep

12

यह कोशिश की जाँच करने के लिए यदि कॉलबैक वस्तु अभी भी मान्य है:

इस मामले में
(((ICommunicationObject)myCallbackObject).State == CommunicationState.Opened) 

myCallbackObject वस्तु जिसके माध्यम से आप कॉलबैक प्रदर्शन कर सकते हैं, एक कॉलबैक अनुबंध

+5

इस समाधान की अनुशंसा नहीं की जाती है क्योंकि जब आप राज्य के लिए जांच करते हैं और जब आप चैनल के साथ कुछ भी करते हैं तो कॉलबैक चैनल को दोषी ठहराया जा सकता है। – LxL

+2

हाँ आपको अभी भी किसी भी अपवाद को संभालना चाहिए क्योंकि निश्चित रूप से जांचने का कोई तरीका नहीं है। –

संबंधित मुद्दे