2011-10-20 18 views
18

इसलिए मैंने अपने डब्ल्यूसीएफ एप्लिकेशन में थोड़ा सा प्रदर्शन करने का फैसला किया है, और चैनल और चैनल फैक्टरी को कैश करने का प्रयास किया है। मेरे पास इसके बारे में दो प्रश्न हैं जो मुझे शुरू करने से पहले साफ़ करने की ज़रूरत है।डब्ल्यूसीएफ चैनल और चैनल फैक्टरी कैशिंग

1) क्या चैनलफैक्टरी को सिंगलटन के रूप में लागू किया जाना चाहिए?

2) मैं अलग-अलग चैनलों को कैश/पुन: उपयोग करने के बारे में अनिश्चित हूं। क्या आपके पास कोई उदाहरण है कि आप इसे कैसे साझा कर सकते हैं?

यह ध्यान रखना महत्वपूर्ण है कि मेरी डब्ल्यूसीएफ सेवा केवल एक एंडपॉइंट के साथ अकेले स्टैंड एप्लिकेशन के रूप में तैनात की जा रही है।

संपादित करें:

आप प्रतिक्रिया के लिए धन्यवाद। मेरे पास अभी भी कुछ प्रश्न हैं ...

1) मुझे लगता है कि मैं कैशिंग होने के कारण भ्रमित हूं। मैं एक क्लाइंट एपीआई वितरित कर रहा हूं जो इस कोड का उपयोग हमारी कंपनी के किसी अन्य विभाग में करता है। क्या यह कैशिंग क्लाइंट पर होती है?

2) क्लाइंट एपीआई का उपयोग सिल्वरलाइट एप्लिकेशन के हिस्से के रूप में किया जाएगा, क्या यह कुछ भी बदलता है? विशेष रूप से, इस तरह के परिदृश्य में कैशिंग तंत्र क्या उपलब्ध हैं?

3) मैं अभी भी GetChannelFactory विधि के डिज़ाइन के बारे में स्पष्ट नहीं हूं। अगर मेरे पास केवल एक ही सेवा है, तो केवल एक चैनलफैक्टरी को कभी बनाया और कैश किया जाना चाहिए?

(क्योंकि मैं पूरी तरह से है कि यह कैसे किया जाना चाहिए के बारे में उलझन हूँ!) मैं अभी भी किसी भी कैशिंग सुविधा को लागू नहीं किया है, लेकिन यहाँ क्या मैं अब तक ग्राहक प्रॉक्सी के लिए है:

namespace MyCompany.MyProject.Proxies 
{ 
    static readonly ChannelFactory<IMyService> channelFactory = 
     new ChannelFactory<IMyService>("IMyService"); 

    public Response DoSomething(Request request) 
    { 
     var channel = channelFactory.CreateChannel(); 

     try 
     { 
      Response response = channel.DoSomethingWithService(request); 
      ((ICommunicationObject)channel).Close(); 
      return response; 
     } 
     catch(Exception exception) 
     { 
      ((ICommenicationObject)channel).Abort(); 
     } 
    } 
} 
+0

# 3 के लिए, हाँ, केवल एक चैनल फैक्ट्री बनाई जानी चाहिए। असल में, आपके पास प्रत्येक सेवा समाप्ति के लिए एक चैनल फैक्ट्री होगी। मेरे मामले में, हमारे पास लगभग 6 स्तर हैं, मुख्य रूप से 2 स्तरों में फैले हुए हैं। आपके मामले में, यदि आपके पास केवल एक ही सेवा है, तो एक ऐप द्वारा उपयोग करें, आप बस जो कर रहे हैं वह कर सकते हैं। आप उपरोक्त कोड सही रास्ते पर हैं। कैशिंग ऐप की जरूरतों पर आधारित होगी। – Tim

+0

@Tim- आपकी सभी मदद के लिए धन्यवाद। मेरे द्वारा सच में इसकी प्रशंसा की जाती है! मुझे लगता है कि मेरे मामले में, तथ्य यह है कि मेरी सेवा इतनी "सरल" थी जिससे मुझे इन अन्य उदाहरणों पर भ्रम पैदा हो रहा था जहां कई अंतराल थे। मुझे = कम उलझन में = टिम ने एक महान काम समझाया! धन्यवाद दोस्त! – Didaxis

+0

आपका स्वागत है। खुशी है कि मैं मदद कर सकता हूँ - खुश कोडिंग! – Tim

उत्तर

20

उपयोग फैक्ट्री का एक उदाहरण बनाने के लिए चैनलफैक्टरी, फिर उस उदाहरण को कैश करें। फिर आप कैश किए गए आचरण से आवश्यक/वांछित के रूप में communicatino चैनल बना सकते हैं।

क्या आपको कई चैनल कारखानों की आवश्यकता है (यानी, क्या कई सेवाएं हैं)? मेरे अनुभव में, वह जगह है जहां आप प्रदर्शन में सबसे बड़ा लाभ देखेंगे। एक चैनल बनाना एक काफी सस्ता काम है; यह शुरुआत में सबकुछ स्थापित कर रहा है जिसमें समय लगता है।

मैं व्यक्तिगत चैनलों को कैश नहीं करता - मैं उन्हें बनाउंगा, उन्हें एक ऑपरेशन के लिए उपयोग करें, और फिर उन्हें बंद करें। यदि आप उन्हें कैश करते हैं, तो वे समय निकाल सकते हैं और चैनल गलती करेगा, फिर आपको इसे निरस्त करना होगा और वैसे भी एक नया बनाना होगा।

यह सुनिश्चित नहीं है कि आप चैनलफैक्टरी को लागू करने के लिए सिंगलटन का उपयोग क्यों करना चाहते हैं, खासकर यदि आप इसे बनाने और इसे कैश करने जा रहे हैं, और केवल एक एंडपॉइंट है।

जब मैं थोड़ा और समय लेता हूं तो मैं बाद में कुछ उदाहरण कोड पोस्ट करूंगा।

अद्यतन: कोड उदाहरण

यहाँ मैं कैसे काम पर एक परियोजना के लिए इस कार्यान्वित का एक उदाहरण है। मैंने ChannelFactory<T> का उपयोग किया, क्योंकि जिस एप्लिकेशन को मैं विकसित कर रहा था वह कई सेवाओं के साथ एक एन-स्तरीय ऐप है, और अधिक जोड़ा जाएगा। लक्ष्य प्रति दिन एक बार ग्राहक बनाने के लिए एक आसान तरीका था, और फिर आवश्यकतानुसार संचार चैनल बनाएं। विचार की मूल बातें मेरी नहीं हैं (मुझे इसे वेब पर एक लेख से मिला है), हालांकि मैंने अपनी आवश्यकताओं के लिए कार्यान्वयन में संशोधन किया।

मेरे पास मेरे आवेदन में एक स्थिर सहायक वर्ग है, और उस कक्षा के भीतर मेरे पास एक शब्दकोश और चैनफेल फैक्ट्री से संचार चैनल बनाने का एक तरीका है।

शब्दकोश निम्नानुसार है (वस्तु मूल्य है क्योंकि इसमें विभिन्न चैनल कारखानियां होंगी, प्रत्येक सेवा के लिए एक)। मैंने उदाहरण में "कैश" को प्लेसहोल्डर के प्रकार के रूप में रखा है - जो भी कैशिंग तंत्र आप उपयोग कर रहे हैं उसके साथ सिंटैक्स को प्रतिस्थापित करें।

public static Dictionary<string, object> OpenChannels 
{ 
    get 
    { 
     if (Cache["OpenChannels"] == null) 
     { 
      Cache["OpenChannels"] = new Dictionary<string, object>(); 
     } 

     return (Dictionary<string, object>)Cache["OpenChannels"]; 
    } 
    set 
    { 
     Cache["OpenChannels"] = value; 
    } 
} 

अगला कारखाना उदाहरण से संचार चैनल बनाने का एक तरीका है। विधि यह देखने के लिए जांचती है कि कारखाना पहले मौजूद है या नहीं - अगर ऐसा नहीं होता है, तो यह इसे बनाता है, इसे शब्दकोश में डालता है और फिर चैनल उत्पन्न करता है। अन्यथा यह कारखाने के कैश किए गए उदाहरण से बस एक चैनल उत्पन्न करता है।

public static T GetFactoryChannel<T>(string address) 
{ 

    string key = typeof(T.Name); 

    if (!OpenChannels.ContainsKey(key)) 
    { 
     ChannelFactory<T> factory = new ChannelFactory<T>(); 
     factory.Endpoint.Address = new EndpointAddress(new System.Uri(address)); 
     factory.Endpoint.Binding = new BasicHttpBinding(); 
     OpenChannels.Add(key, factory); 
    } 

    T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel(); 

    ((IClientChannel)channel).Open(); 

    return channel; 
} 

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

अंत में, जब मैं इसे एप्लिकेशन में उपयोग करता हूं, तो मैं आम तौर पर एक चैनल बनाता हूं, अपना व्यवसाय करता हूं, और इसे बंद करता हूं (या आवश्यकता होने पर इसे रोक दें)। उदाहरण के लिए:

IMyServiceContract client; 

try 
{ 
    client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress"); 

    client.DoSomething(); 

    // This is another helper method that will safely close the channel, 
    // handling any exceptions that may occurr trying to close. 
    // Shouldn't be any, but it doesn't hurt. 
    Helper.CloseChannel(client); 
} 
catch (Exception ex) 
{ 
    // Something went wrong; need to abort the channel 
    // I also do logging of some sort here 
    Helper.AbortChannel(client); 
} 

उम्मीद है कि उपर्युक्त उदाहरण आपको आगे बढ़ने के लिए कुछ देंगे। मैं उत्पादन के माहौल में लगभग एक साल के लिए इस तरह का कुछ उपयोग कर रहा हूं और यह बहुत अच्छा काम करता है। 99% किसी भी समस्या का सामना करना पड़ता है आमतौर पर आवेदन के बाहर कुछ (या तो बाहरी क्लाइंट या डेटा स्रोत हमारे प्रत्यक्ष नियंत्रण में नहीं) से संबंधित होते हैं।

अगर मुझे कुछ स्पष्ट नहीं है या आपके पास और प्रश्न हैं तो मुझे बताएं।

+0

धन्यवाद टिम। आपने वास्तव में कुछ मूल्यवान जानकारी प्रदान की है। मैं निश्चित रूप से आपके उदाहरण के लिए देख रहा हूँ! – Didaxis

+0

@ user384080 - कोड मेरे उत्तर में है। यदि यह स्पष्ट नहीं है, तो मुझे बताएं। धन्यवाद। – Tim

+0

@Tim आपके कार्यान्वयन में एक बग है। आप कॉन्ट्रैक्ट प्रकार से कारखानों को कैश करते हैं इससे कोई फर्क नहीं पड़ता कि पता क्या है। आपके पास एक कुंजी होनी चाहिए जिसमें अनुबंध प्रकार और पता दोनों हो। – Anubis

5

तुम हमेशा सिर्फ अपने ChannelFactory प्रत्येक WCF अनुबंध के लिए स्थिर कर सकता है ...

आप जानते हैं कि नेट 3.5 से प्रॉक्सी वस्तुओं चैनल कारखाने द्वारा प्रदर्शन कारणों से जमा कर रहे हैं होना चाहिए। ICommunicationObject.Close() विधि को कॉल करने से वास्तव में ऑब्जेक्ट को पूल में वापस आ जाता है, जिसकी पुन: उपयोग की जा सकती है।

यदि आप कुछ अनुकूलन करना चाहते हैं तो मैं प्रोफाइलर को देखूंगा, अगर आप अपने कोड में केवल एक आईओ कॉल को रोक सकते हैं तो यह चैनल फैक्ट्री के साथ आपके द्वारा किए गए किसी भी अनुकूलन से कहीं अधिक हो सकता है। ऑप्टिमाइज़ करने के लिए कोई क्षेत्र न चुनें, यह पता लगाने के लिए कि आप ऑप्टिमाइज़ेशन को लक्षित कर सकते हैं, प्रोफाइलर का उपयोग करें। उदाहरण के लिए यदि आपके पास SQL ​​डेटाबेस है, तो आपको शायद आपके प्रश्नों में कुछ कम लटकते फल मिलेंगे जो आपको परिमाण प्रदर्शन के आदेश प्राप्त करेंगे यदि इन्हें पहले ही अनुकूलित नहीं किया गया है।

3

चैनल बनाना प्रदर्शन को इतना खर्च करता है। असल में, डब्ल्यूसीएफ में पहले से ही चैनलफैक्टरी के लिए कैश तंत्र है यदि आप शुद्ध चैनलफैक्टरी के बजाय क्लाइंटबेस में क्लाइंटबेस का उपयोग करते हैं। लेकिन यदि आप कुछ एंडीशनल ऑपरेशंस करते हैं तो कैश की समयसीमा समाप्त हो जाएगी (यदि आप चाहें तो विवरण के लिए कृपया इसे Google करें)। एरोक्स के मुद्दे के लिए मुझे एक और समाधान मिला, मुझे लगता है कि यह बेहतर है। नीचे देखें:


namespace ChannelFactoryCacheDemo 
{ 
    public static class ChannelFactoryInitiator 
    { 
     private static Hashtable channelFactories = new Hashtable(); 

     public static ChannelFactory Initiate(string endpointName) 
     { 
      ChannelFactory channelFactory = null; 

      if (channelFactories.ContainsKey(endpointName))//already cached, get from the table 
      { 
       channelFactory = channelFactories[endpointName] as ChannelFactory; 
      } 
      else // not cached, create and cache then 
      { 
       channelFactory = new ChannelFactory(endpointName); 
       lock (channelFactories.SyncRoot) 
       { 
        channelFactories[endpointName] = channelFactory; 
       } 
      } 
      return channelFactory; 
     } 
    } 
    class AppWhereUseTheChannel 
    { 
     static void Main(string[] args) 
     { 
      ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint"); 
     } 
    } 

    interface IMyContract { } 
} 

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

+0

ध्यान दें कि 'लॉक' गलत तरीके से उपयोग किया जाता है। लॉक को 'कंटेनसकी' पर भी कॉल पर ले जाना चाहिए। –

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