2010-01-05 10 views
29

में प्रतिनिधि को पास और निष्पादित करें मैं अलग-अलग ऐपडोमेन में प्रतिनिधि के साथ कोड के कुछ टुकड़े को निकालना चाहता हूं। मैं यह कैसे कर सकता हूँ?अलग-अलग ऐपडोमेन

UPD1: मेरी समस्या मेरे कार्यक्रम प्रसंस्करण के बारे में कुछ और जानकारी कुछ डेटा (एक यात्रा है:, डीबी से कुछ डेटा प्राप्त यह मूल्यांकन करने और रनटाइम पर विधानसभाओं बनाने के लिए, गतिशील विधानसभाओं निष्पादित और डीबी के लिए परिणाम बारे में)।

वर्तमान समाधान: प्रत्येक पुनरावृत्ति अलग थ्रेड में चल रहा है। बेहतर समाधान: प्रत्येक पुनरावृत्ति अलग-अलग ऐपडोमेन (गतिशील asseblies को उतारने के लिए) में चल रहा है।

UPD2: सभी, उत्तर के लिए धन्यवाद।

मैं इस सूत्र में मेरे लिए एक मिल गया है: Replacing Process.Start with AppDomains

उत्तर

47

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

इसके लिए काम करने के लिए आपके ऑब्जेक्ट को मार्शलबीरफॉब से उत्तराधिकारी होना है।

यहाँ एक उदाहरण है:

public interface IRuntime 
    { 
     bool Run(RuntimesetupInfo setupInfo); 
    } 

    // The runtime class derives from MarshalByRefObject, so that a proxy can be returned 
    // across an AppDomain boundary. 
    public class Runtime : MarshalByRefObject, IRuntime 
    { 
     public bool Run(RuntimeSetupInfo setupInfo) 
     { 
      // your code here 
     } 
    } 

    // Sample code follows here to create the appdomain, set startup params 
    // for the appdomain, create an object in it, and execute a method 
    try 
    { 
     // Construct and initialize settings for a second AppDomain. 
     AppDomainSetup domainSetup = new AppDomainSetup() 
     { 
      ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase, 
      ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, 
      ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName, 
      LoaderOptimization = LoaderOptimization.MultiDomainHost 
     }; 

     // Create the child AppDomain used for the service tool at runtime. 
     childDomain = AppDomain.CreateDomain(
      "Your Child AppDomain", null, domainSetup); 

     // Create an instance of the runtime in the second AppDomain. 
     // A proxy to the object is returned. 
     IRuntime runtime = (IRuntime)childDomain.CreateInstanceAndUnwrap(
      typeof(Runtime).Assembly.FullName, typeof(Runtime).FullName); 

     // start the runtime. call will marshal into the child runtime appdomain 
     return runtime.Run(setupInfo); 
    } 
    finally 
    { 
     // runtime has exited, finish off by unloading the runtime appdomain 
     if(childDomain != null) AppDomain.Unload(childDomain); 
    } 

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

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

जैसा कि उदाहरण में कोड किया गया है, मूल एपडोमेन वास्तव में आईरंटिम और रनटाइम असेंबली दोनों को लोड करना समाप्त कर देगा, लेकिन ऐसा इसलिए है क्योंकि CreateInstanceAndUnwrap के कॉल में मैं असेंबली नाम और पूरी तरह से योग्य प्रकार प्राप्त करने के लिए टाइपऑफ (रनटाइम) का उपयोग कर रहा हूं नाम। आप इसके बजाय फ़ाइल से इन तारों को हार्डकोड या पुनर्प्राप्त कर सकते हैं - जो निर्भरता को कम कर देगा।

ऐपडोमेन पर 'डॉकबैक' नामक एक विधि भी है जो ऐसा लगता है कि यह एक विदेशी ऐपडोमेन में एक प्रतिनिधि को कॉल करने की अनुमति देता है। हालांकि, प्रतिनिधि प्रकार जो इसे लेता है वह है 'CrossAppDomainDelegate'। इसकी परिभाषा है:

public delegate void CrossAppDomainDelegate() 

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

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

+0

CreateInstanceAndUnwrap विधि एक त्रुटि फेंक रही है जिसमें कहा गया है कि यह असेंबली नहीं ढूंढ सकता है (टाइपोफ (रनटाइम) .ssembly.FullName) । यह मेरे लिए एक वेब सर्वर पर चल रहा है और पूर्ण नाम का प्रारूप "myhostdll, संस्करण = 1.0.0.0, संस्कृति = तटस्थ, PublicKeyToken = null" है। – Triynko

+0

@Triynko, नया ऐपडोमेन सेटअप बनाते समय, उसी डोमेन फ़ोल्डर को मास्टर डोमेन के रूप में निर्दिष्ट करने का प्रयास करें, या कम से कम, उस स्थान का उपयोग करें जहां नया डोमेन असेंबली प्राप्त कर सके। –

3

यह आपके प्रश्न के सीधे जवाब नहीं देता, लेकिन शायद यह बेहतर हो अन्य AppDomain में एक WCF सेवा या वेब सेवा बनाने के लिए अलगाव की रक्षा करने के होगा। मैं आपकी विशेष स्थिति को नहीं जानता लेकिन अलग वास्तुशिल्प डिजाइन लगभग हमेशा जाने का सही तरीका है।

+3

नामित पाइप का उपयोग करना, ज़ाहिर है। – Will

+0

असल में, मैं ऐसी सेवा बना रहा हूं। और मैं अलग-अलग डोमेन में प्रत्येक अनुरोध निष्पादित करना चाहता हूं। –

6

आपको .NET Remoting पर और विशेष रूप से Remote Objects पर पढ़ने की आवश्यकता है क्योंकि ये सभी आप AppDomains से गुजर सकते हैं।

लंबी और यह की कमी है कि आपके वस्तु या तो (क प्रॉक्सी के माध्यम से) संदर्भ द्वारा मूल्य या द्वारा पारित कर दिया है।

मूल्य के अनुसार आपकी वस्तु Serializable होनी चाहिए। प्रतिनिधि serializable afaik नहीं हैं। इसका मतलब है कि यह पालन करने के लिए एक अच्छा रास्ता नहीं है।

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

सब कुछ, यह मुश्किल होगा। हो सकता है कि आप अपने प्रतिनिधियों को पूर्ण रूप से सीरियलज़ेबल ऑब्जेक्ट्स बनाने पर विचार करना चाहें ताकि उन्हें आसानी से रिमोटिंग के साथ स्थानांतरित किया जा सके (और अन्य तकनीकों के साथ अच्छी तरह से काम करेगा)।

+0

क्या आप वाकई किसी भी प्रतिनिधि का उपयोग कर सकते हैं? जैसा कि मैं देख सकता हूं, जैसा कि मैंने अपनी पोस्ट में उल्लेख किया है, आप केवल 'CrossAppDomainDelegate' के प्रतिनिधि का उपयोग कर सकते हैं – Phil

8

किसी अन्य ऐपडोमेन पर एक प्रतिनिधि को निष्पादित करने के लिए आप System.AppDomain.DoCallBack() का उपयोग कर सकते हैं। लिंक किए गए एमएसडीएन पेज का एक उत्कृष्ट उदाहरण है। ध्यान दें कि आप केवल CrossAppDomainDelegate के प्रतिनिधियों का उपयोग कर सकते हैं।

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