2010-09-18 17 views
6

मैं एक विंडोज़ ऐप से विंडोज़ सेवा से इंटर-प्रोसेस डब्ल्यूसीएफ संचार करने के लिए netNamedPipeBinding का उपयोग कर रहा हूं।उपयोग में कॉलबैक के साथ बंद कनेक्शन पर डब्ल्यूसीएफ अपवाद

अब मेरा ऐप अन्य सभी खातों में अच्छी तरह से चल रहा है (डब्ल्यूसीएफ अपवादों के मेरे उचित हिस्से से लड़ने के बाद डब्ल्यूसीएफ के साथ काम करने वाले किसी भी व्यक्ति को पता चलेगा ..) लेकिन यह त्रुटि वह है जो काफी लचीला साबित हो रही है।

मेरे परिदृश्य की एक तस्वीर पेंट करने के लिए: मेरी विंडोज़ सेवा को विंडोज ऐप में दबाए गए बटन के माध्यम से किसी भी समय कुछ काम करने के लिए कतारबद्ध किया जा सकता है और फिर netNamedPipeBinding पर बात करता है जो कि बाध्यकारी है जो कॉलबैक का समर्थन करता है (दो -वे संचार) यदि आप परिचित नहीं हैं और इस काम को करने का अनुरोध शुरू करते हैं, (इस मामले में एक फ़ाइल अपलोड प्रक्रिया) यह फ़ाइल प्रगति से स्थानांतरित करने के लिए हर कुछ सेकंड कॉलबैक (घटनाओं) को भी गति देता है। विंडोज ऐप के लिए, तो कुछ काफी तंग क्लाइंट-सर्वर एकीकरण है; इस तरह मैं अपने विंडोज़ ऐप में अपनी विंडोज़ सेवा में जो चल रहा है उसकी प्रगति प्राप्त करता हूं।

अब, सभी महान हैं, डब्ल्यूसीएफ देवताओं ने अभी मेरे साथ अपेक्षाकृत खुश हैं, एक बार जब मैं ऐप को समय-समय पर बंद कर देता हूं (जो एक पूरी तरह से मान्य परिदृश्य है)। जबकि एक हस्तांतरण का कार्य प्रगति पर है, और कॉलबैक बहुत भारी फायरिंग कर रहे हैं, मैं इस त्रुटि मिलती है:

System.ServiceModel.ProtocolException: 
    The channel received an unexpected input message with Action 
    'http://tempuri.org/ITransferServiceContract/TransferSpeedChangedCallback' 
    while closing. You should only close your channel when you are not expecting 
    any more input messages. 

अब मैं उस त्रुटि को समझते हैं, लेकिन दुर्भाग्य से मैं कभी नहीं किसी भी अधिक इनपुट messsages प्राप्त करने के बाद अपने चैनल को बंद करने के गारंटी नहीं दे सकते, के रूप में उपयोगकर्ता किसी भी समय ऐप को बंद कर सकता है इसलिए काम अभी भी विंडोज सेवा की पृष्ठभूमि में जारी रहेगा (जैसे वायरस स्कैनर कैसे काम करता है)। उपयोगकर्ता को जीत प्रबंधन टूल ऐप को शुरू और बंद करने में सक्षम होना चाहिए जितना उन्हें हस्तक्षेप नहीं होता है।

अब त्रुटि, मुझे अपना Unsubscribe() कॉल करने के तुरंत बाद प्राप्त होता है जो ऐप को समाप्त करने से पहले दूसरा अंतिम कॉल है और मुझे विश्वास है कि डब्ल्यूसीएफ क्लाइंट को डिस्कनेक्ट करने का पसंदीदा तरीका क्या है। कनेक्शन को बंद करने से पहले सभी सदस्यता रद्द करने से पहले क्लाइंट आईडी को एक सरणी से हटा दिया जाता है जो स्थानीय रूप से जीत सेवा wcf सेवा पर संग्रहीत किया जाता है (क्योंकि यह एक जीत है जो जीत सेवा और विंडोज ऐप दोनों द्वारा साझा किया जाता है क्योंकि जीत सेवा काम कर सकती है अनुसूचित घटनाएं स्वयं ही) और क्लाइंट आईडी सरणी हटाने के बाद मैं निष्पादित करता हूं, जो मुझे उम्मीद है (महसूस) एक स्वच्छ डिस्कनेक्शन होना चाहिए।

इसका परिणाम, अपवाद प्राप्त करने के अलावा, मेरा ऐप लटकता है, यूआई कुल लॉक अप, प्रगति सलाखों और सब कुछ मध्य मार्ग में है, जिसमें रेस हालत या डब्ल्यूसीएफ डेडलॉक [श्वास] होने के संकेत देने वाले सभी संकेत हैं, लेकिन अब मैं काफी धागा-समझदार हूं और मुझे लगता है कि यह अपेक्षाकृत अलग स्थिति है और अपवाद को पढ़ने के रूप में है, मुझे नहीं लगता कि यह एक 'धागा' मुद्दा है, क्योंकि यह प्रारंभिक डिस्कनेक्शन का एक मुद्दा बताता है फिर मेरे सभी धागे को मेहेम में सर्पिल करता है, शायद ताला लगा देता है।

public void Unsubscribe() 
    { 
     try 
     { 
      // Close existing connections 
      if (channel != null && 
       channel.State == CommunicationState.Opened) 
      { 
       proxy.Unsubscribe(); 
      } 
     } 
     catch (Exception) 
     { 
      // This is where we receive the 'System.ServiceModel.ProtocolException'. 
     } 
     finally 
     { 
      Dispose(); 
     } 
    } 

और मेरे Dispose() विधि है, जो स्वच्छ डिस्कनेक्ट करने होंगे::

public void Dispose() 
    { 
     // Dispose object 
     if (channel != null) 
     { 
      try 
      { 
       // Close existing connections 
       Close(); 
       // Attempt dispose object 
       ((IDisposable)channel).Dispose(); 
      } 
      catch (CommunicationException) 
      { 
       channel.Abort(); 
      } 
      catch (TimeoutException) 
      { 
       channel.Abort(); 
      } 
      catch (Exception) 
      { 
       channel.Abort(); 
       throw; 
      } 
     } 
    } 

और WCF सेवा Subscription() समकक्ष और वर्ग

ग्राहक पर मेरे Unsubscribe() दृष्टिकोण इस तरह दिखता है विंडोज सेवा सर्वर पर गुण (संदर्भ के लिए) (यहां कुछ भी मुश्किल नहीं है और मेरा अपवाद होता है ग्राहक के पक्ष):

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, 
    ConcurrencyMode = ConcurrencyMode.Multiple)] 
    public class TransferService : LoggableBase, ITransferServiceContract 
    { 
     public void Unsubscribe() 
     { 
      if (clients.ContainsKey(clientName)) 
      { 
       lock (syncObj) 
       { 
        clients.Remove(clientName); 
       } 
      } 

#if DEBUG 
      Console.WriteLine(" + {0} disconnected.", clientName); 
#endif 
     } 
     ... 
    } 

इंटरफेस की:

[ServiceContract(
    CallbackContract = typeof(ITransferServiceCallbackContract), 
    SessionMode = SessionMode.Required)] 
public interface ITransferServiceContract 
{ 
    [OperationContract(IsInitiating = true)] 
    bool Subscribe(); 

    [OperationContract(IsOneWay = true)] 
    void Unsubscribe(); 
    ... 
} 

कॉलबैक अनुबंध के इंटरफेस है, यह बहुत ही रोमांचक कुछ भी नहीं है, सिर्फ प्रतिनिधियों के माध्यम से घटनाओं आदि कारण मैं इस शामिल दिखाने के लिए है कॉल आप मेरे गुण।

[CallbackBehavior(UseSynchronizationContext = false, 
ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class TransferServiceCallback : ITransferServiceCallbackContract 
{ ... } 

सच आशा किसी को मेरी मदद कर सकते हैं: मैं पहले से ही UseSynchronizationContext = false शामिल करके गतिरोध का एक सेट को कम किया! बहुत बहुत धन्यवाद :) :)

+0

मैं विशिष्ट मुद्दे के बारे में पता नहीं है, लेकिन जानकारी के लिए सूत्रण घपला लगता है * संभवतः कारण कैसे WCF सिंक संदर्भ (जो WinForms आदि में फ़ॉर्म है) का उपयोग करता है करने के लिए *। –

+0

धन्यवाद मार्क, हाँ जिसने मुझे पकड़ा और मैंने उस मुद्दे पर पढ़कर डेडलॉक्स के एक सेट को कम किया, चाल को कॉलबैक अनुबंध पर 'UseSynchronizationContext = false' सेट करना था;) मैं इसे अपने उदाहरणों में जोड़ दूंगा। – GONeale

+0

आह, दाएं; यह देखने के लिए अच्छा है कि आप इसे पहले ही कवर कर चुके हैं; पी –

उत्तर

11

ओह मेरे भगवान, मुझे यह समस्या मिली।

उस अपवाद को अंडरलिंग ऐप हैंग से कोई लेना देना नहीं था, यह केवल एक सावधानी पूर्वक अपवाद था जिसे आप सुरक्षित रूप से पकड़ सकते हैं।

आप इस पर विश्वास नहीं करेंगे, मैंने इस बग पर लगभग 6 घंटे चालू और बंद किया है, यह channel.Close() लंबित डब्ल्यूसीएफ अनुरोधों को पूरा करने के लिए लॉक अप करने के लिए बंद हो गया है (जो हस्तांतरण समाप्त होने तक कभी पूरा नहीं होगा! उद्देश्य को हरा देता है!)

मैं बस लाइन के बाद ब्रूट-फोर्स ब्रेकपॉइंटिंग लाइन चला गया, मेरी समस्या यह थी कि मैं बहुत धीमी थी ..... यह कभी नहीं लटका होगा, क्योंकि किसी भी तरह से चैनल बंद होने के लिए उपलब्ध होगा (यहां तक ​​कि पहले भी स्थानांतरण समाप्त हो गया था) इसलिए मुझे F5 को तोड़ना पड़ा और फिर तुरंत लटकने के लिए कदम उठाना पड़ा, और यही वह लाइन है जिस पर यह समाप्त हो गया। अब मैं बस Close() ऑपरेशन के लिए टाइमआउट मान लागू करता हूं और TimeoutException के साथ इसे पकड़ता हूं और फिर चैनल को समय-समय पर बंद नहीं कर सकता है, तो मुश्किल से चैनल को रोक दें!

ठीक कोड देखें:

private void Close() 
{ 
    if (channel != null && 
     channel.State == CommunicationState.Opened) 
    { 
     // If cannot cleanly close down the app in 3 seconds, 
     // channel is locked due to channel heavily in use 
     // through callbacks or the like. 
     // Throw TimeoutException 
     channel.Close(new TimeSpan(0, 0, 0, 3)); 
    } 
} 

public void Dispose() 
{ 
    // Dispose object 
    if (channel != null) 
    { 
     try 
     { 
      // Close existing connections 
      // ***************************** 
      // This is the close operation where we perform 
      //the channel close and timeout check and catch the exception. 
      Close(); 

      // Attempt dispose object 
      ((IDisposable)channel).Dispose(); 
     } 
     catch (CommunicationException) 
     { 
      channel.Abort(); 
     } 
     catch (TimeoutException) 
     { 
      channel.Abort(); 
     } 
     catch (Exception) 
     { 
      channel.Abort(); 
      throw; 
     } 
    } 
} 

मैं अंत में खत्म हो गया और साथ किया इस बग के लिए बहुत खुश हूँ! वर्तमान डब्ल्यूसीएफ सेवा राज्य के बावजूद मेरा ऐप अब 3 सेकंड टाइमआउट के बाद साफ-सफाई बंद कर रहा है, मुझे आशा है कि मैं किसी और की मदद कर सकता हूं जो कभी भी खुद को इसी तरह के मुद्दे से पीड़ित करता है।

ग्राहम

+0

_That अपवाद को अंडरलिंग ऐप लटकाने के साथ कुछ लेना देना नहीं था, जो कि केवल एक सावधानी पूर्वक अपवाद था सुरक्षित रूप से पकड़ सकते हैं ._ क्या आपके पास एक संदर्भ लिंक है जो इस तरह प्रोटोकॉल अपवादों को निगलने की सुरक्षा से बात करता है? मेरे साथ भी ठीक यही समस्या है। – lesscode

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