locked
Using dynamically loaded dll from dynamically created class RRS feed

  • Question

  • I can dynamically load a dll and use it fine.  But when a dynamically compile new code that uses the dynamically loaded dll, it fails because it cannot find the dynamically loaded dll that is already in use.  I can fix this by putting the dynamically loaded dll in the same path as the application itself, but my question is how to I do this without having to force the dynmically loaded dll in the same path?

    I am using Visual studio 2005.

    Below is example program that fails.

    using

     

    System;

    using

     

    System.Collections.Generic;

    using

     

    System.Text;

    using

     

    System.Reflection;

    using

     

    System.CodeDom.Compiler;

    using

     

    Microsoft.CSharp;

    namespace

     

    ConsoleApplication1

    {

     

    class Program

    {

     

    static void Main(string[] args)

    {

     

    // Dynically loaded dll with fully qualified path

     

    Assembly dynAssem = Assembly.LoadFile(@"E:\RB_TED\X45R\Tests\ConsoleApplication1\DynamicDll\bin\Debug\DynamicDll.dll");

     

    // Create instance of Class from dynamically loaded dll

     

    Type type = MyFindType(dynAssem, "Class1");

    CommonDll.

    BaseClass DynamicClass = (CommonDll.BaseClass)Activator.CreateInstance(type);

     

    // Works fine.

    DynamicClass.Hello();

     

    foreach (PropertyInfo pInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))

    {

     

    Console.WriteLine("Type = " + pInfo.PropertyType);

    }

     

    // Now compile a new class that references the dynamically loaded class

     

    string sourceCode =

     

    "using System;" +

     

    "namespace CreatedDllNamespace" +

     

    "{" +

     

    "public class CreatedClass" +

     

    "{" +

     

    "private DynamicDll.Class1 myVar = new DynamicDll.Class1();" +

     

    "public DynamicDll.Class1 MyProperty" +

     

    "{" +

     

    " get { return myVar; }" +

     

    " set { myVar = value; }" +

     

    "}" +

     

    "}" +

     

    "}";

     

    CompilerParameters compilerOptions = new CompilerParameters();

    compilerOptions.GenerateExecutable =

    false;

    compilerOptions.GenerateInMemory =

    true;

     

    Assembly[] assems = AppDomain.CurrentDomain.GetAssemblies();

     

    foreach (Assembly assem in assems)

    {

    compilerOptions.ReferencedAssemblies.Add(assem.Location);

    }

     

    CSharpCodeProvider compiler = new CSharpCodeProvider();

     

    CompilerResults results = compiler.CompileAssemblyFromSource(compilerOptions, sourceCode);

     

    if (results.Errors.HasErrors)

    {

     

    Console.WriteLine(results.Errors.ToString());

    }

     

    else

    {

     

    Type CreatedClassType = MyFindType(results.CompiledAssembly, "CreatedClass");

     

    // This fails because it cannot load the already loaded dynamically loaded dll

     

    foreach (PropertyInfo pInfo in CreatedClassType.GetProperties(BindingFlags.Public | BindingFlags.Instance))

    {

     

    Console.WriteLine("Type = " + pInfo.PropertyType);

    }

     

    // This fails because it cannot load the already loaded dynamically loaded dll

     

    object obj = Activator.CreateInstance(CreatedClassType);

    }

    }

     

    static public Type MyFindType(Assembly assembly, string typeName)

    {

     

    Type returnObject = null;

     

    foreach (Type type in assembly.GetTypes())

    {

     

    if (type.IsClass == true)

    {

     

    if (string.Compare(type.Name, typeName, true) == 0)

    {

    returnObject = type;

     

    break;

    }

    }

    }

     

    return returnObject;

    }

    }

    }

    Tuesday, December 1, 2009 3:48 PM

Answers

  • I have had trouble with generating in memory dll's so someone else will have to help you. In the interim this code works for me and you just have to drop the .exe when you are done. Putting it in a separate AppDomain is a good idea anyway.
     

    String Code = String.Empty;
                CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
                string [] SourceCode = new string[1];
    
                Code += "using System; using System.IO; namespace PlayingAround { class NewCode { static void Main() { ";
                Code += "Console.Title = \"New Thread\"; Console.BackgroundColor = ConsoleColor.Blue; Console.ForegroundColor = ConsoleColor.White; ";
                Code += "Console.BufferHeight = 1000; for (int BigNum = 0; BigNum < 20000; BigNum++) Console.WriteLine(BigNum); } } } ";
                
                SourceCode[0] = Code;
                
                // compile the class in memory
                CompilerParameters parms = new CompilerParameters();
            
                parms.GenerateExecutable = true;  // right now writes out an exe file
    
                parms.CompilerOptions = "/optimize";
                parms.ReferencedAssemblies.Add("System.dll");
                parms.OutputAssembly = "Dyn.exe";
    
                CompilerResults results = provider.CompileAssemblyFromSource(parms, SourceCode);
    
                AppDomain dom = AppDomain.CreateDomain("Dyncode", null);
                dom.ExecuteAssembly("Dyn.exe");
        
                AppDomain.Unload(dom);


    Tuesday, December 1, 2009 4:35 PM