c# - एक सम्मेलन को सभी संदर्भों के साथ दोबारा सम्मिलित करने के लिए कैसे लोड करें?




.net reflection (6)

मैं एक नई ऐपडोमेन को कुछ असेंबली लोड करना चाहता हूं जिसमें एक जटिल संदर्भ पेड़ है (MyDll.dll -> माइक्रोसॉफ्ट.ऑफिस.इंटरोप.एक्ससेल.dll -> माइक्रोसॉफ्ट.वीबी.इंटरोप.dll -> Office.dll -> stdole.dll )

जहां तक ​​मुझे समझ में आया, जब AppDomain को एक असेंबली लोड की जा रही है, तो इसके संदर्भ स्वचालित रूप से लोड नहीं होंगे, और मुझे उन्हें मैन्युअल रूप से लोड करना होगा। तो जब मैं करता हूं:

string dir = @"SomePath"; // different from AppDomain.CurrentDomain.BaseDirectory
string path = System.IO.Path.Combine(dir, "MyDll.dll");

AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = dir;
AppDomain domain = AppDomain.CreateDomain("SomeAppDomain", null, setup);

domain.Load(AssemblyName.GetAssemblyName(path));

और FileNotFoundException मिला:

फ़ाइल या असेंबली 'MyDll, संस्करण = 1.0.0.0, संस्कृति = तटस्थ, PublicKeyToken = null' या इसकी निर्भरताओं में से एक लोड नहीं हो सका। सिस्टम निर्दिष्ट फाइल का पता लगाने में नाकामयाब रहा।

मुझे लगता है कि मुख्य हिस्सा इसकी निर्भरताओं में से एक है

ठीक है, मैं domain.Load(AssemblyName.GetAssemblyName(path)); से पहले करता domain.Load(AssemblyName.GetAssemblyName(path));

foreach (AssemblyName refAsmName in Assembly.ReflectionOnlyLoadFrom(path).GetReferencedAssemblies())
{
    domain.Load(refAsmName);
}

लेकिन एक और (संदर्भित) असेंबली पर फिर से FileNotFoundException मिला।

सभी संदर्भों को बार-बार कैसे लोड करें?

रूट असेंबली लोड करने से पहले मुझे संदर्भ पेड़ बनाना है? इसे लोड किए बिना असेंबली के संदर्भ कैसे प्राप्त करें?


अपने नए ऐपडोमेन पर, AssemblyResolve रीसोल्व इवेंट हैंडलर सेट करने का प्रयास करें। एक घटना निर्भर होने पर उस घटना को बुलाया जाता है।


आपकी प्रॉक्सी ऑब्जेक्ट विदेशी एप्लिकेशन डोमेन में निष्पादित होने से पहले आपको CreateInstanceAndUnwrap को आमंत्रित करने की आवश्यकता है।

 class Program
{
    static void Main(string[] args)
    {
        AppDomainSetup domaininfo = new AppDomainSetup();
        domaininfo.ApplicationBase = System.Environment.CurrentDirectory;
        Evidence adevidence = AppDomain.CurrentDomain.Evidence;
        AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);

        Type type = typeof(Proxy);
        var value = (Proxy)domain.CreateInstanceAndUnwrap(
            type.Assembly.FullName,
            type.FullName);

        var assembly = value.GetAssembly(args[0]);
        // AppDomain.Unload(domain);
    }
}

public class Proxy : MarshalByRefObject
{
    public Assembly GetAssembly(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFile(assemblyPath);
        }
        catch (Exception)
        {
            return null;
            // throw new InvalidOperationException(ex);
        }
    }
}

साथ ही, ध्यान दें कि यदि आप FileNotFound उपयोग करते हैं LoadFrom आपको एक FileNotFound अपवाद मिलेगा क्योंकि असेंबली रिज़ॉल्वर जीएसी या वर्तमान एप्लिकेशन के बिन फ़ोल्डर में लोड होने वाली असेंबली को खोजने का प्रयास करेगा। इसके बजाय एक मनमानी असेंबली फ़ाइल लोड करने के लिए LoadFile का उपयोग करें - लेकिन ध्यान दें कि यदि आप ऐसा करते हैं तो आपको स्वयं निर्भरताओं को लोड करने की आवश्यकता होगी।


कुंजी AppDomain द्वारा उठाए गए असेंबली रिसेल्व घटना है।

[STAThread]
static void Main(string[] args)
{
    fileDialog.ShowDialog();
    string fileName = fileDialog.FileName;
    if (string.IsNullOrEmpty(fileName) == false)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        if (Directory.Exists(@"c:\Provisioning\") == false)
            Directory.CreateDirectory(@"c:\Provisioning\");

        assemblyDirectory = Path.GetDirectoryName(fileName);
        Assembly loadedAssembly = Assembly.LoadFile(fileName);

        List<Type> assemblyTypes = loadedAssembly.GetTypes().ToList<Type>();

        foreach (var type in assemblyTypes)
        {
            if (type.IsInterface == false)
            {
                StreamWriter jsonFile = File.CreateText(string.Format(@"c:\Provisioning\{0}.json", type.Name));
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                jsonFile.WriteLine(serializer.Serialize(Activator.CreateInstance(type)));
                jsonFile.Close();
            }
        }
    }
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string[] tokens = args.Name.Split(",".ToCharArray());
    System.Diagnostics.Debug.WriteLine("Resolving : " + args.Name);
    return Assembly.LoadFile(Path.Combine(new string[]{assemblyDirectory,tokens[0]+ ".dll"}));
}

मुझे @ user1996230 के उत्तर को समझने में थोड़ी देर लग गई, इसलिए मैंने एक और स्पष्ट उदाहरण प्रदान करने का निर्णय लिया। नीचे दिए गए उदाहरण में मैं किसी अन्य ऐपडोमेन में लोड ऑब्जेक्ट के लिए प्रॉक्सी बना देता हूं और उस ऑब्जेक्ट पर किसी अन्य डोमेन से एक विधि कॉल करता हूं।

class ProxyObject : MarshalByRefObject
{
    private Type _type;
    private Object _object;

    public void InstantiateObject(string AssemblyPath, string typeName, object[] args)
    {
        assembly = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + AssemblyPath); //LoadFrom loads dependent DLLs (assuming they are in the app domain's base directory
        _type = assembly.GetType(typeName);
        _object = Activator.CreateInstance(_type, args); ;
    }

    public void InvokeMethod(string methodName, object[] args)
    {
        var methodinfo = _type.GetMethod(methodName);
        methodinfo.Invoke(_object, args);
    }
}

static void Main(string[] args)
{
    AppDomainSetup setup = new AppDomainSetup();
    setup.ApplicationBase = @"SomePathWithDLLs";
    AppDomain domain = AppDomain.CreateDomain("MyDomain", null, setup);
    ProxyObject proxyObject = (ProxyObject)domain.CreateInstanceFromAndUnwrap(typeof(ProxyObject).Assembly.Location,"ProxyObject");
    proxyObject.InstantiateObject("SomeDLL","SomeType", new object[] { "someArgs});
    proxyObject.InvokeMethod("foo",new object[] { "bar"});
}

यदि आप संदर्भित असेंबली जीएसी में या सीएलआर के प्रोबिंग पथ पर नहीं हैं, तो आपको AppDomain.AssemblyResolve या AppDomain.ReflectionOnlyAssembly ईवेंट को पुन: स्थापित करें (आप किस भार के आधार पर कर रहे हैं)।

AssemblyResolve

AppDomain.ReflectionOnlyAssemblyResolve


http://support.microsoft.com/kb/837908/en-us

सी # संस्करण:

एक मॉडरेटर क्लास बनाएं और इसे MarshalByRefObject से MarshalByRefObject :

class ProxyDomain : MarshalByRefObject
{
    public Assembly GetAssembly(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFrom(assemblyPath);
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException(ex.Message);
        }
    }
}

ग्राहक साइट से कॉल करें

ProxyDomain pd = new ProxyDomain();
Assembly assembly = pd.GetAssembly(assemblyFilePath);




appdomain