0

I'm looking to embed and load dll files into my class library so that it can be contained in one dll.
I have a Class Library called Wraper.
I'm using a Console application called ConsoleApp to run the Wraper Class Library.

class Program
{
    static void Main(string[] args)
    {
        Wallet X  = new Wallet();
        X.SendPayment("1", "Driver={ODBC Driver 17 for SQL Server};Server=.;Database=Home;Trusted_Connection=yes;");
    }
}

I have my dll files in the Wraper project in a folder called EmbeddedAssemblies
I'm wanting to load these files in my project. Here is the code that I have in my Wraper Class Library:

public void SendPayment(string DCode, string ConnectionString)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        ...
        Console.WriteLine("A break point WILL stop here.");
        ...
    }

// This method does not seem to run. Why????
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        ...
        Console.WriteLine("A break point WILL NOT stop here.");
        ...
        string baseResourceName = Assembly.GetExecutingAssembly().GetName().Name + "." + new AssemblyName(args.Name).Name;
        byte[] assemblyOdbc = null;
        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Wraper.EmbeddedAssemblies.System.Data.Odbc.dll"))
        {
            assemblyOdbc = new Byte[stream.Length];
            stream.Read(assemblyOdbc, 0, assemblyOdbc.Length);
        }
        byte[] assemblyNewton = null;
        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Wraper.EmbeddedAssemblies.Newtonsoft.Json.dll"))
        {
            assemblyNewton = new Byte[stream.Length];
            stream.Read(assemblyNewton, 0, assemblyNewton.Length);
        }
        Console.WriteLine("loaded");
        return Assembly.Load(assemblyOdbc, assemblyNewton);
    }

I'm not sure why this is not working it builds with no errors however when I put a break point just inside the CurrentDomain_AssemblyResolve method it does not even go to the break point, thus the assembly(s) do not load.
What am I doing wrong?

Quest
  • 1
  • 1
  • AssemblyResolve doesn't run --> There is nothing to resolve. How do you use and reference types in EmbeddedAssemblies? – shingo Feb 24 '22 at 08:43
  • One basic explanation is that the code subscribes the event too late. It is the just-in-time compiler that needs the assembly, it necessarily runs early so any statement inside SendPayment() that needs a type from the loaded assemblies can't be compiled. – Hans Passant Feb 24 '22 at 10:11
  • @HansPassant are you saying that the code to load the assembley has to be loaded from the Main method in the ConsoleApp? If so is there a work around? I don't has access to that area. – Quest Feb 24 '22 at 14:24

1 Answers1

0

the code to load the assembley has to be loaded from the Main method in the ConsoleApp? If so is there a work around? I don't has access to that area

Yes. The common workaround is to hook AssemblyResolve in a static constructor of the type that references the assembly. That's early enough becuse:

It initializes the class before the first instance is created or any static members declared in that class (not its base classes) are referenced. A static constructor runs before an instance constructor.

In particular the static constructor runs before any of the type's methods are JITted, which is when referenced assemblies need to be available.

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67
  • So I added a contructor and put the **AppDomain.CurrentDomain.AssemblyResolve** code in and it still want fire/resolve. `static Wallet() { string resource1 = "WalletWrapper.EmbeddedAssemblies.System.Data.Odbc.dll"; EmbeddedAssembly.Load(resource1, "System.Data.Odbc.dll"); AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; }` – Quest Feb 24 '22 at 18:10