There was a need to bring part of the code to the server as a DLL. The task is to download a DLL into memory, and use DLL methods from memory. I found one answer for my task, but I don’t understand how to call my method.

WebClient webClient = new WebClient(); byte[] assemblyBytes = webClient.DownloadData("https://mysite.com"); var assembly = Assembly.Load(assemblyBytes); var types = assembly.DefinedTypes; 

How to call DLL methods downloaded to memory? For example, a DLL is written in C # and has such a structure.

 class myClass { public static int GetSum(int arg) { return arg; } public static int GetNum(int arg) { return arg; } public static int GetId(int arg) { return arg; } } 
  • Can you describe the essence of the problem a little more specifically Do you have information about this dll mi on what is written dll itself and all that. - Kamushek
  • @Kamushek added an example of the structure of the DLL - user304204
  • @DigitalCore, listen! :) Speech about how to connect dll, you can through marshaling, but you have your own vision of solutions. My answer considered a different way. - NewView

3 answers 3

An example of calling a static method:

 var type = assembly.GetType("Namespace.TypeName"); var method = type.GetMethod("StaticMethod"); var result = method.Invoke(null, new object[] { param1, param2 }); 

But the best thing would be to specify a certain interface / base class in your program, and the class in the downloaded dll should implement the interface / inherit the class. For example, like this:

 // интСрфСйс Π² вашСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅ public interface IRemote { int DoSomething(string param1, int param2); } // Π΅Π³ΠΎ рСализация Π² скачиваСмой Π΄Π»Π», ΠΎΠ½Π° Π΄ΠΎΠ»ΠΆΠ½Π° ΠΈΠΌΠ΅Ρ‚ΡŒ рСфСрСнс Π½Π° Π²Π°ΡˆΡƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ public class RemoteClass : IRemote { public int DoSomething(string param1, int param2) { Console.WriteLine(param1); } } 

And then you do this:

 var type = assembly.GetType("Namespace.RemoteClass"); var remote = (IRemote)Activator.CreateInstance(type); remote.DoSomething("qwerty", 100); 

The advantages of this approach are that you do not need to get each method using GetMethod , and errors are eliminated when incorrect parameters are passed when calling MethodInfo.Invoke .

  • 2
    The answers of all the users are correct, this one was perfect for my tasks. - user304204 pm

If you have already coped with the task of loading a DLL into memory, then the matter will remain small. Suppose the code example you give is:

 WebClient webClient = new WebClient(); byte[] assemblyBytes = webClient.DownloadData("https://mysite.com"); var assembly = Assembly.Load(assemblyBytes); 

And as a result of the execution of this code, we got an assembly into the assembly variable. Now, based on the knowledge of the type name and the method being called, you can get the type and call the method from it as follows:

 // ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ Ρ‚ΠΈΠΏ (ΠΌΡ‹ Π·Π½Π°Π΅ΠΌ Π΅Π³ΠΎ имя - myClass) Type type = assembly.GetType("myClass"); // создадим экзСмпляр ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π·Π°Π΄Π°Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° var obj = Activator.CreateInstance(type); // Π²Ρ‹Π·ΠΎΠ²Π΅ΠΌ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΈΠ· ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠ³ΠΎ экзСмпляра Ρƒ Π·Π°Π΄Π°Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° type.InvokeMember( "GetSum", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, obj, new Object[] {5} ); 

For everything to work successfully, you need to take into account some of the nuances. The type myClass either should not have any constructors at all, so that the non-parametric constructor by default created the CLR for us, or there should be one non-parametric constructor so that Activator.CreateInstance can instantiate the object. Also, the type names must be correct, if there is a mismatch there will be an error. The last parameter of the Type.InvokeMember method is an array with arguments passed to the called member (method).

  • one
    Thanks for the help, the answer helped me master the basic principles. - user304204

If the library you need is known at compile time, you can refer to it just as you would any other. Just do not forget to remove it from the output directory (for example, through the Post Build Event) when the compiler automatically copies it there. Or, for those familiar with MSBuild, you can play around with the Reference metadata.

To download such an assembly from the server, you will need:

  1. subscribe to the AppDomain.CurrentDomain.AssemblyResolve event and return the assembly when the CLR tries to load it and does not find it;

  2. make sure that none of your methods called before loading the assembly refers to the classes from that assembly.

This will not work like this:

 void Foo() { AppDomain.CurrentDomain.AssemblyResolve += ...; myClass.getId(0); } 

And this is how it will be:

 void Foo() { AppDomain.CurrentDomain.AssemblyResolve += ...; Bar(); } void Bar() { myClass.getId(0); } 
  • The second method may be non-working on mono. Microsoft dotnet loads as if line by line, mono - file by file. Plus a minus, did not penetrate deeply. - Monk