Loading DLLs at runtime in C# - c#

I am trying to figure out how you could go about importing and using a .dll at runtime inside a C# application. Using Assembly.LoadFile() I have managed to get my program to load the dll (this part is definitely working as I am able to get the name of the class with ToString()), however I am unable to use the 'Output' method from inside my console application. I am compiling the .dll then moving it into my console's project. Is there an extra step between CreateInstance and then being able to use the methods?
This is the class in my DLL:
namespace DLL
{
using System;
public class Class1
{
public void Output(string s)
{
Console.WriteLine(s);
}
}
}
and here is the application I want to load the DLL
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(#"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
c.Output(#"Hello");
}
Console.ReadLine();
}
}
}

Members must be resolvable at compile time to be called directly from C#. Otherwise you must use reflection or dynamic objects.
Reflection
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(#"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {#"Hello"});
}
Console.ReadLine();
}
}
}
Dynamic (.NET 4.0)
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(#"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
dynamic c = Activator.CreateInstance(type);
c.Output(#"Hello");
}
Console.ReadLine();
}
}
}

Right now, you're creating an instance of every type defined in the assembly. You only need to create a single instance of Class1 in order to call the method:
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(#"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
var theType = DLL.GetType("DLL.Class1");
var c = Activator.CreateInstance(theType);
var method = theType.GetMethod("Output");
method.Invoke(c, new object[]{#"Hello"});
Console.ReadLine();
}
}

You need to create an instance of the type that expose the Output method:
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(#"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
var class1Type = DLL.GetType("DLL.Class1");
//Now you can use reflection or dynamic to call the method. I will show you the dynamic way
dynamic c = Activator.CreateInstance(class1Type);
c.Output(#"Hello");
Console.ReadLine();
}

Activator.CreateInstance() returns an object, which doesn't have an Output method.
It looks like you come from dynamic programming languages? C# is definetly not that, and what you are trying to do will be difficult.
Since you are loading a specific dll from a specific location, maybe you just want to add it as a reference to your console application?
If you absolutely want to load the assembly via Assembly.Load, you will have to go via reflection to call any members on c
Something like type.GetMethod("Output").Invoke(c, null); should do it.

foreach (var f in Directory.GetFiles(".", "*.dll"))
Assembly.LoadFrom(f);
That loads all the DLLs present in your executable's folder.
In my case I was trying to use Reflection to find all subclasses of a class, even in other DLLs. This worked, but I'm not sure if it's the best way to do it.
EDIT: I timed it, and it only seems to load them the first time.
Stopwatch stopwatch = new Stopwatch();
for (int i = 0; i < 4; i++)
{
stopwatch.Restart();
foreach (var f in Directory.GetFiles(".", "*.dll"))
Assembly.LoadFrom(f);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
}
Output:
34
0
0
0
So one could potentially run that code before any Reflection searches just in case.

It's not so difficult.
You can inspect the available functions of the loaded object, and if you find the one you're looking for by name, then snoop its expected parms, if any. If it's the call you're trying to find, then call it using the MethodInfo object's Invoke method.
Another option is to simply build your external objects to an interface, and cast the loaded object to that interface. If successful, call the function natively.
This is pretty simple stuff.

Related

Can't load dll files as an embedded resource to my class library

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?
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.

C# Assembly ressolver doesn't start when instantiating variable but from function it does

Hi I have simple client to write value to UA server. I am using OpcLabs libraries in VS2017, Win10 NetFr 4.8. Libraries are loaded from other folder than executable. When dlls are in the same folder both methods below works, when resolver should be triggered = dlls are not in folder - it is not.
The problem is simple. Resolver:
private static Assembly OpcAssRes(object sender, ResolveEventArgs args)
{
var ProgramFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
string OpcAsmPath = Path.Combine(ProgramFiles, "OPC Labs QuickOPC 2020.2", "Assemblies", "net47");
var ReqAss = new AssemblyName(args.Name).Name;
foreach (string FAssName in Directory.GetFiles(OpcAsmPath, "*.dll"))
{
if (Path.GetFileNameWithoutExtension(FAssName) == ReqAss)
{
var DLL = Assembly.LoadFrom(FAssName);
return DLL;
}
}
return null;
}
And when I want to instantiate the client using the method from libraries:
Works:
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += OpcAssRes;
ClCon();
}
static void ClCon()
{
var cl = new EasyUAClient();
}
Does NOT work - Exception is immediately raised, that the library cannot be found. I tried even sleep it before resolver, but it doesnt - instant Exception- like the resolver isnt triggered. When breakpoint is added in resolver, it does not get to it = it is not started.:
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += OpcAssRes;
var cl = new EasyUAClient();
}
Is it normal? Thanks for your advices.
Types used in a method are loaded before the method is called. If you bind your assembly resolver inside a method that uses a type in an external assembly, the loader won't be bound yet.

How to load a class from .cs file and use it in code

I want to load a class form a .cs file and use it in another code.
Assume I have a .cs file which contains code like that:
//some imports
public class Commands
{
//a lot of commands
}
What I am trying is to load this class from a file using CSharpCodeProvider or whatever and create a list of Commands.
A piece of code from a console app.
list<Commands> lst;
The question is how can I load Commands class dynamically (at runtime) (without restarting the console app or starting VS) and create the list of Commands?
Try this example, which I have put together and tested:
Build program.cs as a .Net Framework Console App in e.g. Visual Studio.
// program.cs
using System;
using System.IO;
using System.CodeDom.Compiler;
using System.Reflection;
namespace RuntimeCompile
{
class Program
{
static void Main(string[] args)
{
// Get a path to the file(s) to compile.
FileInfo sourceFile = new FileInfo("mySource.cs");
Console.WriteLine("Loading file: " + sourceFile.Exists);
// Prepary a file path for the compiled library.
string outputName = string.Format(#"{0}\{1}.dll",
Environment.CurrentDirectory,
Path.GetFileNameWithoutExtension(sourceFile.Name));
// Compile the code as a dynamic-link library.
bool success = Compile(sourceFile, new CompilerParameters()
{
GenerateExecutable = false, // compile as library (dll)
OutputAssembly = outputName,
GenerateInMemory = false, // as a physical file
});
if (success)
{
// Load the compiled library.
Assembly assembly = Assembly.LoadFrom(outputName);
// Now, since we didn't have reference to the library when building
// the RuntimeCompile program, we can use reflection to create
// and use the dynamically created objects.
Type commandType = assembly.GetType("Command");
// Create an instance of the loaded class from its type information.
object commandInstance = Activator.CreateInstance(commandType);
// Invoke the method by name.
MethodInfo sayHelloMethod = commandType.GetMethod("SayHello", BindingFlags.Public | BindingFlags.Instance);
sayHelloMethod.Invoke(commandInstance, null); // no arguments, no return type
}
Console.WriteLine("Press any key to exit...");
Console.Read();
}
private static bool Compile(FileInfo sourceFile, CompilerParameters options)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFile.FullName);
if (results.Errors.Count > 0)
{
Console.WriteLine("Errors building {0} into {1}", sourceFile.Name, results.PathToAssembly);
foreach (CompilerError error in results.Errors)
{
Console.WriteLine(" {0}", error.ToString());
Console.WriteLine();
}
return false;
}
else
{
Console.WriteLine("Source {0} built into {1} successfully.", sourceFile.Name, results.PathToAssembly);
return true;
}
}
}
}
In the output directory (bin), next to the console app executable place a text file named mySource.cs with this content:
// mySource.cs
using System;
internal class Program
{
static void Main()
{
Console.WriteLine("Hello from mySource!");
Console.ReadLine();
}
}
public class Command
{
public void SayHello()
{
Console.WriteLine("Hello (Command)");
}
}
Then run the first console app and observe it's output. It should log "Hello (Command)", showing that the code was correctly compiled, loaded and executed.
The example shows how to use the CodeDom.Compiler to compile a cs-file at runtime and then load it as dll to run code within it. Be aware, that almost no error handling was implemented.
This should answer the question, but there may still be better approaches to handling your use-case. In case of plugin loading it makes sense to use interfaces which are added as a reference to both assemblies to avoid the use of reflection, etc.
There is probably a better way to achieve your overall goal, like dependency injection.
However, you can do it with the ICodeCompiler.
See this article https://support.microsoft.com/en-ca/help/304655/how-to-programmatically-compile-code-using-c-compiler
To load the c# class from another c# class you need to use "using"
using Commands;
public class class1
{
private list<Commands>lst;
//...
}

Compiler says dynamic property is missing but I can see it

I'm starting to dive into the world of C# Dynamics and Metaprogramming, and having some trouble.
I managed to create a CodeDom tree, and generate the following code:
namespace Mimsy {
using System;
using System.Text;
using System.Collections;
internal class JubJub {
private int _wabeCount;
private ArrayList _updates;
public JubJub(int wabeCount) {
this._updates = new ArrayList();
this.WabeCount = wabeCount;
}
public int WabeCount {
get {
return this._wabeCount;
}
set {
if((value < 0))
this._wabeCount = 0;
else
this._wabeCount = value;
this._updates.Add(this._wabeCount);
}
}
public string GetWabeCountHistory() {
StringBuilder result = new StringBuilder();
int ndx;
for(ndx = 0; (ndx < this._updates.Count); ndx = ndx + 1) {
if((ndx == 0))
result.AppendFormat("{0}", this._updates[ndx]);
else
result.AppendFormat(", {0}", this._updates[ndx]);
}
}
}
}
I am then compiling dynamically this namespace to an assembly named "dummy".
I can succesfully get an instance of this Type:
string typeName = "Mimsy.JubJub";
Type type = dummyAssembly.GetType(typeName);
dynamic obj = Activator.CreateInstance(type, new object[] { 8 });
//obj is a valid instance type
If I debug this code, I can see in the debugger that obj actually has the property WabeCount:
However, when trying to access this property, the compiler shouts that the dynamic property does not exist.
There are one or perhaps two problems with your code:
You are using an internal class, and trying to access it with dynamic. The two things don't play well together. See https://stackoverflow.com/a/18806787/613130. Use public clasas
You need to cast the value before assigning it to wabeCount, like:
obj.WabeCount = (int)wabes[ndx]
Note that technically, if your "main" assembly is strong named, you could add the InternalsVisibleToAttribute to the "dynamic" assembly to make its internal "things" visible to the main assembly... I do think it would be wasted work.

"An object reference is required for the non-static field, method or property." while compiling C# code at runtime

I have a public class, "CodeCompiler", which allows me to compile and run C# code at run-time. Just like IDEs work.
When I click the "button1" it creates code at run-time, compiles and executes.
My main Form1 contains a TextBox control called "textbox1". In order to make changes on that "textbox1" by runtime I made this button1_Click event.
But when I click it, it shows me a run-time error...
Compiler Errors :
Line 14,34 : An object reference is required for the non-static field, method, or property 'Compiling_CSharp_Code_at_Runtime.Form1.textBox1'
It showed me when I was editing the text data on that "textbox1". But if I will try to make changes about other property like "Size", "Location" then imagine what will happen!
using System;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace Compiling_CSharp_Code_at_Runtime
{
public class CodeCompiler
{
public CodeCompiler()
{
}
public object ExecuteCode(string code, string namespacename, string classname,
string functionname, bool isstatic,
string[] References1, params object[] args)
{
object returnval = null;
CompilerParameters compilerparams = new CompilerParameters();
for (int i = 0; i <= References1.GetUpperBound(0); i++)
{
compilerparams.ReferencedAssemblies.Add(References1[i]);
}
Assembly asm = BuildAssembly(code, compilerparams);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
private Assembly BuildAssembly(string code, CompilerParameters compilerparams)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CodeCompiler cc = new CodeCompiler();
string SourceCode1 = #"
using Compiling_CSharp_Code_at_Runtime;
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace N1
{
public class C1
{
public static void F1(string st1, string st2)
{
Compiling_CSharp_Code_at_Runtime.Form1.textBox1.Text += ""This is a DEMO "" st1 + st2.ToUpper();
}
}
}";
string namespace1 = "N1", class1 = "C1", function1 = "F1";
bool IsStatic = true;
object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic, new string[] { "Compiling CSharp Code at Runtime.exe", "System.Windows.Forms.dll", "System.Drawing.dll", "System.ComponentModel.dll", "System.dll" }, "arg1", "arg2");
}
}
}
I found many problems related to this problem on this site where a suggestion was:
"It looks like I am calling a non static property from a static method.
I should either make the property static, or create an instance of Form1."
But even creation an instance of Form1 was difficult at runtime!
The problem appears to be that you're not passing reference to the Form1 on which you want code to be executed to CodeCompiler at all. The fact that you're calling it within your Form1 doesn't change anything - objects don't automatically learn anything about the object using them. (If they did, things would be a lot more complicated.)
The way you're accessing Form1 is also incorrect - you're using the typename (by the way, as a fully-qualified path which is pointless, because while the class C1 is not in the same namespace as Form1, you include Form1's namespace in the compiled code via using) to refer to a non-static member of the type. The instance member textBox1 of the type Form1 can be accessed only from some instance, but there's no logical way to access the Form1 object. What if you'd instantiated 10 of them? How would the decision be made which of those 10 to return to your call?
What you should do, if you want to continue down this path (and I'm not really sure why you're trying to mimic eval() in C# - you're throwing away a lot of the safety that makes C# nice and easy to work with), is pass a reference to the Form1 instance you want altered either in the constructor of CodeCompiler or in the ExecuteCode method. I think the latter would probably make more sense.
You should change your SourceCode1 so that it looks like this (this also fixes a typo in the original code, restoring a missing + character):
string SourceCode1 = #"
using Compiling_CSharp_Code_at_Runtime;
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace N1
{
public class C1
{
public static void F1(string st1, string st2, Form1 formToExecuteOn)
{
formToExecuteOn.textBox1.Text +=
""This is a DEMO "" + st1 + st2.ToUpper();
}
}
}";
Then call the ExecuteCode() method like this:
object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic,
new string[] { "Compiling CSharp Code at Runtime.exe",
"System.Windows.Forms.dll", "System.Drawing.dll",
"System.ComponentModel.dll", "System.dll" },
"arg1", "arg2", this);
This will compile the code such that the Form1 instance to be used can be passed to the method when it's invoked. And the reference to that Form1 instance is provided in the argument list that is actually passed for the method invocation (i.e. the last argument, this)..
Granted, even if that works, it'll only allow you to execute code on Form1 objects. The greater point of this is that if you're going to go down this path, you need to be passing reference to anything you want altered to CodeCompiler somehow. I'm not sure whether object objectToChange would work instead of formToChange, and how much information the compiler is going to need about the object you're passing in order to execute code on it.
And once more, for feeling: you need a very, very unique use case to make any of this even remotely a good use of time or sanity. (You have to pass seven precisely-constructed objects, mostly strings, to ExecuteCode() every single time you want to run anything!)

Categories