C# Custom AppDomain

C# Custom AppDomain: जैसाकि हमने पहले भी कहा कि किसी Window Process में AppDomain.CreateDomain() नाम के Static Method के माध्‍यम से एक ही समय पर एक से ज्यादा Application Domains Host हो सकते हैं।

हालांकि बहुत ही कम परिस्थितियों में हम किसी Process में नया Custom AppDomain Create करते हैं। फिर भी इसकी Working को समझना हमारे लिए उपयोगी है क्योंकि ये हमें बहुत ही Unique Type की Requirements को पूरा करने की क्षमता प्रदान करता है।

उदाहरण के लिए यदि हम Dynamic Assemblies Create करते हैं, तो हमें उन Dynamic Assemblies को किसी न किसी Custom AppDomain में ही Add करना होता है। इसके अलावा विभिन्न .NET Security APIs को Use करते समय भी ये जरूरी होता है कि हम इस बात को समझें कि नया AppDomain किस तरह से Create किया जाए ताकि Supplied Security Credentials के आधार पर अन्‍य Assemblies को Current AppDomain से Isolated रखा जाए।

किसी Application के Process में नया Custom AppDomain Create करने के लिए हमें AppDomain.CreateDomain() Method Use करना होता है, जिसे कई तरह से Overload किया गया है। फिर भी हमें नया AppDomain() Create करने के लिए इस Method को Use करते समय कम से कम एक Friendly Name को इस Method में Parameter के रूप में Specify करना जरूरी होता है।

File Name: CreatingCustomAppDomain.cs
using System;
using System.Linq;

namespace CSharpMultiThreading
{
    class CustomApplicationDomain
    {
        static void Main(string[] args)
        {
            // Show all loaded assemblies in default AppDomain.
            AppDomain defaultAD = AppDomain.CurrentDomain;
            ListAllAssembliesInAppDomain(defaultAD);

            // Make a new AppDomain.
            MakeNewAppDomain();
            Console.ReadLine();
        }

        private static void MakeNewAppDomain()
        {
            // Make a new AppDomain in the current process and list loaded assemblies.
            AppDomain newAD = AppDomain.CreateDomain("SecondAppDomain");
            ListAllAssembliesInAppDomain(newAD);
        }

        static void ListAllAssembliesInAppDomain(AppDomain ad)
        {
            // Now get all loaded assemblies in the default AppDomain.
            var loadedAssemblies = from a in ad.GetAssemblies() orderby a.GetName().Name select a;
            Console.WriteLine("***** Here are the assemblies loaded in {0}*****",ad.FriendlyName);

            foreach (var a in loadedAssemblies)
            {
                Console.WriteLine("-> Name: {0}", a.GetName().Name);
                Console.WriteLine("-> Version: {0}\n", a.GetName().Version);
            }
        }
    }
}

Output:
***** Here are the assemblies loaded in CreatingCustomAppDomain.exe *****
-> Name: CreatingCustomAppDomain
-> Version: 0.0.0.0

-> Name: mscorlib
-> Version: 4.0.0.0

-> Name: System
-> Version: 4.0.0.0

-> Name: System.Core
-> Version: 4.0.0.0

***** Here are the assemblies loaded in SecondAppDomain *****
-> Name: mscorlib
-> Version: 4.0.0.0

इस Program में ListAllAssembliesInAppDomain()MakeNewAppDomain() नाम के दो Static Methods Create किए गए हैं, जहां ListAllAssembliesInAppDomain() नाम का Method Parameter के रूप में Specified AppDomain द्वारा Load सभी Assemblies को Display करता है। जबकि MakeNewAppDomain() नाम का Static Method Current Process में एक नया AppDomain Create करता है।

जब हम इस Program को Run करते हैं, तो Current Application जो कि Default Application Domain है (CreatingCustomAppDomain.exe) में mscorlib.dll, Syste.dll, System.Core.dll CreatingCustomAppDomain.exe नाम की Assemblies Load हो रही हैं।

जबकि हम जो नया AppDomain Create कर रहे हैं, उसमें केवल mscorlib.dll नाम की Assembly ही Loaded है, जो कि किसी भी .NET Application के AppDomain में Default रूप से Loaded होती है।

हालांकि दोनों ही Application Domains के लिए समान Assembly Set Accessible है। लेकिन यहां समझने वाली बात ये है कि Assemblies वास्तव में किसी Process में Load नहीं होती, बल्कि हमेंशा किसी Process के किसी Application Domain में Load होती हैं।

जिस तरह से हम किसी समान Process में कोई Custom Application Domain Create कर सकते हैं, उसी तरह से हम उस Custom Application Domain में किसी Assembly को Dynamically Load भी कर सकते हैं।

चूंकि CLR हमेंशा किसी भी Application के लिए केवल Default Application Domain में ही Assemblies को उस समय Load करता है करता है, जब उनकी जरूरत होती है। लेकिन यदि हम चाहें तो हम जो Custom Application Domain Create करते हैं, हम AppDomain.Load() Static Method का प्रयोग करके उस Newly Created Custom AppDomain में भी किसी Assembly को Dynamically Load कर सकते हैं। इसी तरह से हम AppDomain.ExecuteAssembly() Static Method का प्रयोग करके किसी *.exe Assembly को भी Load कर सकते हैं और उसके Main() Method को Invoke कर सकते हैं।

उदाहरण के लिए मानलो कि हम हमारे Newly Create होने वाले AppDomain में MyLibrary.dll Assembly को Load करना चाहते हैं और हम ये मान लेते हैं कि हमने इस Library File को Current Folder में ही Save कर दिया है, जहां हमारा Current Application या Program File है। इस स्थिति में इस जरूरत को पूरा करने के लिए हम हमारे पिछले Program को ही निम्नानुसार तरीके से Modify कर सकते हैं:

File Name: LoadingAssemblyInCustomAppDomain.cs
using System;
using System.Linq;
using System.IO;

namespace CSharpMultiThreading
{
    class CustomApplicationDomain
    {
        static void Main(string[] args)
        {
            // Show all loaded assemblies in default AppDomain.
            AppDomain defaultAD = AppDomain.CurrentDomain;
            ListAllAssembliesInAppDomain(defaultAD);

            // Make a new AppDomain.
            MakeNewAppDomain();
        }

        private static void MakeNewAppDomain()
        {
            // Make a new AppDomain in the current process.
            AppDomain newAD = AppDomain.CreateDomain("SecondAppDomain");

            try
            {
                // Now load CarLibrary.dll into this new domain.
                newAD.Load("MyLibrary");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }

            // List all assemblies.
            ListAllAssembliesInAppDomain(newAD);
        }

        static void ListAllAssembliesInAppDomain(AppDomain ad)
        {
            // Now get all loaded assemblies in the default AppDomain.
            var loadedAssemblies = from a in ad.GetAssemblies() orderby a.GetName().Name select a;
            Console.WriteLine("*****Here are the assemblies loaded in {0}*****", ad.FriendlyName);

            foreach (var a in loadedAssemblies)
            {
                Console.WriteLine("-> Name: {0}", a.GetName().Name);
                Console.WriteLine("-> Version: {0}\n", a.GetName().Version);
            }
        }
    }
}

Output:
***** Here are the assemblies loaded in CreatingCustomAppDomain.exe *****
-> Name: CreatingCustomAppDomain
-> Version: 0.0.0.0

-> Name: mscorlib
-> Version: 4.0.0.0

-> Name: System
-> Version: 4.0.0.0

-> Name: System.Core
-> Version: 4.0.0.0

***** Here are the assemblies loaded in SecondAppDomain *****
-> Name: mscorlib
	-> Version: 4.0.0.0

-> Name: MyLibrary
-> Version: 0.0.0.0

और जैसाकि हम इस बार के Output में देख सकते हैं कि इस बार हमारे Custom AppDomain में Dynamically MyLibrary को Add कर दिया गया है और ये काम करने के लिए हमने निम्नानुसार तरीके से एक try … catch Block के बीच Load() Method को Use किया है:

            try
            {
                // Now load CarLibrary.dll into this new domain.
                newAD.Load("MyLibrary");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }

जिस तरह से हम किसी Custom New AppDomain() को Create कर सकते हैं, उसी तरह से हम AppDomain.Unload() Method का प्रयोग करके किसी Process से किसी Individual AppDomain को Unload भी कर सकते हैं।

हालांकि CLR किसी भी Individual .NET Assembly को Manually Unload करने की Permission नहीं देता। फिर भी हम AppDomain.Unload() Method का प्रयोग करके किसी AppDomain को उसके Hosting Process से Manually Unload कर सकते हैं और जब हम ऐसा करते हैं, तो जिस Application Domain को हम Unload करते हैं, वह Application Domain स्वयं अपनी हर Assembly को Unload कर देता है।

जब हम किसी Application Domain को Unload करते हैं, तो DomainUnload Event Fire होता है तथा जब Application Domain Process से Exit होता है, तब ProcessExit Event Trigger होता है। इन दोनों Events के साथ भी हम किसी Specific Code को Hook कर सकते हैं।

उदाहरण के लिए जब निम्न Program में हम किसी AppDomain को Unload करते हैं, तो हर Unload होने वाली Assembly के लिए यदि हम कोई Notification प्राप्त करना चाहें, तो इस जरूरत को पूरा करने के लिए हम DomainUnload Event को Use कर सकते हैं:

File Name: UnloadingCustomAppDomain.cs
using System;
using System.Linq;
using System.IO;

namespace CSharpMultiThreading
{
    class CustomApplicationDomain
    {
        static void Main(string[] args)
        {
            // Show all loaded assemblies in default AppDomain.
            AppDomain defaultAD = AppDomain.CurrentDomain;

            defaultAD.ProcessExit += (o, s) => { Console.WriteLine("Default AD unloaded!"); };

            ListAllAssembliesInAppDomain(defaultAD);
            MakeNewAppDomain();
        }

        private static void MakeNewAppDomain()
        {
            // Make a new AppDomain in the current process.
            AppDomain newAD = AppDomain.CreateDomain("SecondAppDomain");

            try
            {
                // Now load CarLibrary.dll into this new domain.
                newAD.Load("MyLibrary");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }

            // List all assemblies.
            ListAllAssembliesInAppDomain(newAD);

            // Now tear down this AppDomain.
            AppDomain.Unload(newAD);
        }

        static void ListAllAssembliesInAppDomain(AppDomain ad)
        {
            // Now get all loaded assemblies in the default AppDomain.
            var loadedAssemblies = from a in ad.GetAssemblies() orderby a.GetName().Name select a;
            Console.WriteLine("**** Here are the assemblies loaded in {0} ****", ad.FriendlyName);

            foreach (var a in loadedAssemblies)
            {
                Console.WriteLine("-> Name: {0}", a.GetName().Name);
                Console.WriteLine("-> Version: {0}\n", a.GetName().Version);
            }
        }
    }
}

Output:
***** Here are the assemblies loaded in CreatingCustomAppDomain.exe *****
-> Name: CreatingCustomAppDomain
-> Version: 0.0.0.0

-> Name: mscorlib
-> Version: 4.0.0.0

-> Name: System
-> Version: 4.0.0.0

-> Name: System.Core
-> Version: 4.0.0.0

***** Here are the assemblies loaded in SecondAppDomain *****
-> Name: mscorlib
	-> Version: 4.0.0.0

-> Name: MyLibrary
	-> Version: 0.0.0.0

Default AD unloaded!

ये Program Exactly पिछले Program जैसा ही है। लेकिन इस Program में हमने हमारे Custom AppDomain में Dynamically Assembly को Add करने के बाद उसे निम्नानुसार Statement द्वारा Unload भी किया है:

AppDomain.Unload(newAD);

और Unload करते समय Trigger होने वाले ProcessExit Event को भी Main() Method में Change करते हुए निम्नानुसार Use किया है:

defaultAD.ProcessExit += (o, s) => { Console.WriteLine(“Default AD unloaded!”); };

परिणामस्वरूप जैसे ही हमारा Newly Added Custom AppDomain को Current Process में Load करके Unload करते हैं, तो Unload होते ही ProcessExit Event Fire होता है, जिसके Response में उपरोक्त Code Run होता है और हमें हमारे Program के Output की अन्तिम Line के अनुसार Result प्राप्त होता है।

Object Context Boundaries in C# Custom AppDomain

जैसाकि हमने पिछले Section में समझा कि AppDomains वास्तव में किसी Process का एक Logical Partition होते हैं, जिसमें .NET Assemblies Host होती हैं। लेकिन हम किसी Application Domain को और भी हिस्सों में Sub-Divide कर सकते हैं, जिसे Context Boundaries के नाम से जाना जाता है। .NET Context हमें किसी Single AppDomain को किसी Specified Object का “Specific Home” Establish करने के लिए एक तरीका Provide करता है।

Context का प्रयोग करके CLR ये क्षमता प्राप्त करता है कि वह Object जिसकी कुछ Runtime Requirements होती हैं, उन्हें एक Appropriate व Consistent Manner में विभिन्न प्रकार के Methods Invoke करके Handle किया जाता है।

उदाहरण के लिए यदि हम [Synchronization] Attribute का प्रयोग करके एक ऐसा C# Class Type Define करते हैं जिसे Automatic Thread Safety की जरूरत हो, तो CLR इस Type को Memory Allocate करते समय “Synchronized Context” Create करता है।

जिस तरह से कोई Process Default AppDomain Define करता है, उसी तरह से हर Application Domain का एक Default Context होता है। इस Default Context को अक्सर Context 0 नाम से भी Refer किया जाता है, क्योंकि ये किसी Process में Create होने वाला सबसे पहला AppDomain होता है। इस Default Context का प्रयोग उन अन्‍य .NET Objects को Group करने के लिए किया जाता है, जिनका कोई Unique या Specific Context नहीं होता।

जैसाकि हम समझ सकते हैं कि ज्यादातर .NET Objects Context 0 में ही Load होते हैं। इसलिए यदि CLR को पता चलता है कि किसी Newly Created AppDomain की Requirements कुछ Special हैं, तो CLR उस AppDomain के लिए एक अलग Context Boundary Create कर देता है, जो कि Hosting Application Domain के अन्दर ही होता है। यानी Global Context में Local Context Create हो जाता है। इस प्रकार से यदि हम चाहें तो Process, AppDomain व Context के बीच की आपसी Relationship को निम्न चित्रानुसार Represent कर सकते हैं:

C# Custom AppDomain - Hindi

ऐसे .NET Objects जिन्हें किसी Special Contextual Treatment की जरूरत नहीं होती, Context-Agile Object कहलाते हैं। इन Objects को Hosting AppDomain में बिना Object के Runtime Requirements को Interfere किए हुए कहीं पर भी Access किया जा सकता है। Context-Agile Object Create करना काफी आसान है, क्योंकि हम जब भी कोई Object Create करते हैं, जो कि System.ContextBoundObject Base Class से Derived न हो, वह इसी प्रकार का Object होता है। जैसे:

class MyClass {}         //Context-Agile Object is loaded into Context 0

जबकि जिन Objects को Contextual Allocation की जरूरत होती है, उन्हें Context-Bound Objects कहा जाता है और ये Objects हमेंशा System.ContextBoundObject Base Class से जरूर Derived होते हैं।

ये Base Class के Objects इसी बात को Represent करते हैं कि ये Objects उसी स्थिति में Normal तरीके से काम कर सकते हैं, जबकि ये उसी Context में Use हों, जहां इन्हें Create किया गया है। परिणामस्वरूप इस Object को यदि इनके Context के अलावा किसी दूसरे Context में Use किया जाए, तो निश्चित रूप से कोई न कोई Exception ही Trigger करते हैं।

साथ ही System.ContextBoundObject Class से Derive करने पर एक Context Sensitive Type भी .NET Attributes की एक Special Category से Related हो जाता है, जिसे Context Attributes के नाम से जाना जाता है। जबकि सभी Context Attributes ContextAttribute नाम की Base Class से Derive होते हैं।

उदाहरण के लिए मानलो कि हम BaseClass नाम की एक Class Create करना चाहते हैं जो कि Automatically Thread Safe Nature की हो। ऐसी Class Define करने के लिए हमें हमारी Class को Create करते समय हमें System.ContextBoundObject से Derive करना होता है और Class को निम्नानुसार तरीके से [Synchronization] Attribute के साथ Specify करना होता है:

	using System.Runtime.Remoting.Contexts;

	// This context-bound type will only be loaded into a
	// synchronized (hence thread-safe) context.
	[Synchronization]
	class BaseClass : ContextBoundObject { }

जिन Types को [Synchronization] Attribute के साथ Specify किया जाता है, वे सभी Types Automatically Thread Safe Context में ही Create होते हैं। चूंकि हमने BaseClass को एक Synchronized Context में Define किया है।

इसलिए यदि हम इस Class के Object को किसी Unsynchronized Context में Use करें, तो हमारा Object Thread Safe नहीं रहेगा। परिणामस्वरूप ये Object विभिन्न प्रकार के Data Corruption का कारण बन सकता है। क्योंकि विभिन्न Threads इस Object से Interact करने की कोशिश करेंगे।

इसलिए CLR BaseClass Objects को कभी भी Synchronized Context से बाहर Move न करे इस बात को Ensure करने के लिए हम BaseClass को ContextBoundObject से Derive करते हैं।

C# AppDomain
Threading in C#

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS