none
How load several assemblies from streams RRS feed

  • Question

  • I can load several assemblies into the current AppDomain using streams and calling pAppDomain.GetAssemblies() and see that they are all loaded.

    Problem is none of the following will instantiate an interface properly.

    If the modules exist as files then everything works just fine.

    Case 1: This fails to find the module even though the module name and type name are fully qualified names and I see them loaded.

                    lSmartModule = (ISmartModule)Activator.CreateInstance(pAppDomain, pModuleName, pTypeName);
                   
    Case 2: This instantiates the class interface and does not fail but actually calls another class method from a totally different module when I call one of the interface methods on the interface returned.

                    Type lType = lAssembly.GetType(pTypeName);
                    lSmartModule = (ISmartModule)Activator.CreateInstance(lType);


    Case 3: Same problem as Case 1 - cannot find the module.

                    lSmartModule = (ISmartModule)pAppDomain.CreateInstanceAndUnwrap(pModuleName, pTypeName);

    Is there some special trick to loading several modules into the AppDomain from some streams and being able to instantiate an interface or class from them? All my modules load so I don't think there is any dependency missing. If the actual assembly file exists in my executable directory everything works.

    Basically what I am trying to do is start an application with some core modules and then load additioanl modules I obtain dynamically and will instantiate the class instances from. The only code combination that sort of works calls the wrong module, class and method!!!

    Thanks, Dave
    • Edited by CodeSlinger Saturday, October 3, 2009 5:30 PM punctuation
    Saturday, October 3, 2009 5:28 PM

Answers

  • OK I have figured out a few things. When loading with bytes rather than a file you have to service the AssemblyResolve event and coff (small joke) up the assembly that you loaded into the appdomain so while loading them, just remember their full names in a dictionary.

    Apparently, you cannot create instances by using code in cases 1 or 3 when loading assemblies with bytes rather than from a file. For one thing, the Assembly's CodeBase is the path of the dll that loaded the assembly by bytes and not something related to the actual assembly that was loaded by bytes.

    In cases 2 and 4, the code was actually working but the associated .pdb file was not loaded so the debugger just showed the first thing it could which was in an assembly that was loaded normally and did have its .pdb file loaded.

    To run, I am basically using a variation of case 4 where I remember the actual assembly that contains the interface I want and then use it to create my instance.

    So the only thing I need now is to figure out how to load the .pdb files so I can debug the assemblies I dynamically loading using bytes.

    All ideas appreciated! Thanks, Dave
    • Marked as answer by CodeSlinger Sunday, October 4, 2009 7:05 AM
    Sunday, October 4, 2009 6:02 AM

All replies

  • You've got a problem with assembly identity.  Review this blog post.

    Hans Passant.
    Saturday, October 3, 2009 7:18 PM
    Moderator
  • Perhaps so in the case of the assembly not found but this would not explain why I go off to never never land in the case that succeeds but calls the wrong module, class and method.

    And in the cases where the assembly is not found I supply the fully qualified name or type which I get from the actual loaded assembly itself as below.

    Here is what happens in the now 4 cases:

                    // I get the name and type from the actual loaded assembly
                    Assembly[] lAssemblies = pAppDomain.GetAssemblies();
                    pModuleName = lAssemblies[12].FullName;
                    Type lType = lAssemblies[12].GetType(pTypeName);

                    // Case 1:
                    //lSmartModule = (ISmartModule)Activator.CreateInstance(pAppDomain, pModuleName, pTypeName);
                    // gets {"Could not load file or assembly 'CmdMan.Console.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.":"CmdMan.Console.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"}
                   
                    // Case 2:
                    //lSmartModule = (ISmartModule)Activator.CreateInstance(lType);
                    // goes to the wrong method in the wrong dll

                    // Case 3:
                    //lSmartModule = (ISmartModule)pAppDomain.CreateInstanceAndUnwrap(pModuleName, pTypeName);
                    // gets same as Case 1

                    // Case 4:
                    //lSmartModule = (ISmartModule)lAssemblies[12].CreateInstance(pTypeName);
                    // gets same as Case 2

                    // run the core object smart module interface
                    lSmartModule.Run(); // either get no interface or this goes to some other assembly, class and method than the one it should!


    • Edited by CodeSlinger Saturday, October 3, 2009 8:19 PM add Run call
    Saturday, October 3, 2009 8:16 PM
  • OK I have figured out a few things. When loading with bytes rather than a file you have to service the AssemblyResolve event and coff (small joke) up the assembly that you loaded into the appdomain so while loading them, just remember their full names in a dictionary.

    Apparently, you cannot create instances by using code in cases 1 or 3 when loading assemblies with bytes rather than from a file. For one thing, the Assembly's CodeBase is the path of the dll that loaded the assembly by bytes and not something related to the actual assembly that was loaded by bytes.

    In cases 2 and 4, the code was actually working but the associated .pdb file was not loaded so the debugger just showed the first thing it could which was in an assembly that was loaded normally and did have its .pdb file loaded.

    To run, I am basically using a variation of case 4 where I remember the actual assembly that contains the interface I want and then use it to create my instance.

    So the only thing I need now is to figure out how to load the .pdb files so I can debug the assemblies I dynamically loading using bytes.

    All ideas appreciated! Thanks, Dave
    • Marked as answer by CodeSlinger Sunday, October 4, 2009 7:05 AM
    Sunday, October 4, 2009 6:02 AM
  • OK I figured it out - just use the other version of Load(byte[], byte[]) where the second byte array is the symbol stream! Cool stuff!
    Sunday, October 4, 2009 7:04 AM