How to call a method from an external Assembly - c#

I have sample c# project:
namespace SampleExe
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
And I have sample c# dll:
namespace SampleDll
{
public class Program
{
public static void TestMethod(string samplestr)
{
Console.WriteLine("TestMethod Void Runned! Your string is: "+samplestr);
}
}
}
How can i call TestMethod() from compilled SampleDll.DLL (i want to load external dll)

Here's a working example of using Reflection to load a library at runtime and execute a static method. Note that it assumes quite a lot: you must know the library name, the class name, the method name, and all of its arguments ahead of time. It's often much easier to just reference a library directly.
A great way to use Reflection successfully is together with inheritance/interfaces. Library A contains the base class or interface, and Library B contains a derived class. Library A can use reflection to load Library B , then find all class types in Library B that are derived from the base class or interface (using Type.IsAssignableFrom). In this way, Library A will have strongly typed properties and methods to work with coming from the base, instead of having to know string names of classes, methods, and properties in Library B a priori.
Code for main EXE doing the reflection:
using System;
using System.IO;
using System.Linq;
using System.Reflection;
namespace SomeNamespace
{
public class Program
{
static void Main()
{
string pathToSampleDLL = "<if you know the path ahead of time, use it>";
// if SampleDLL.dll is in same directory as this EXE (a common occurrence):
string workingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
pathToSampleDLL = Path.Combine(workingDirectory, "SampleDLL.dll");
// load the DLL at runtime
Assembly sampleDLL = Assembly.LoadFrom(pathToSampleDLL);
// since you know the type name, you can use LINQ to return your type:
Type sampleType = sampleDLL.GetTypes().FirstOrDefault(t => t.Name == "Program");
// you are looking for a static method on this type, and you know its name, so use GetMethods:
MethodInfo staticMethod = sampleType.GetMethod("TestMethod", BindingFlags.Public | BindingFlags.Static);
// invoke the method. Since you know its arguments and return value ahead of time, just hard code it:
// you can use null for the object since this is a static method. It takes only one argument, a sample string
staticMethod.Invoke(null, new object[] { "sampleStr" });
}
}
}
Code for sample library (compiled to "SampleDLL.dll"):
using System;
namespace SampleDll
{
public class Program
{
public static void TestMethod(string sampleStr)
{
Console.WriteLine("TestMethod Void Runned! Your string is: " + sampleStr);
}
}
}

You have multiple options for this. You can create a dll and add the dll as a reference to the project. You can add the project as a reference also. You can create a NuGet package of dll also and use that.
Then simply call SampleDll.Program.TestMethod

To do this, you need to use reflection.
var assembly = Assembly.Load(File.ReadAllBytes("SampleDLL.dll"));
foreach(Type type in assembly.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
type.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, c, new object[] { #"Hi!" });
}

Related

How to access running program from dynamically loaded dll

So I'm trying to access a running program from which I've injected an external DLL at runtime. I have two projects: console app and class library.
Console app:
using System;
using System.Reflection;
namespace SharpConsole
{
public class GameEvent
{
private bool _cancelled;
public bool Cancelled { get => _cancelled; }
public void SetCancelled(bool cancelled)
{
_cancelled = cancelled;
}
public override string ToString()
{
return $"Event (Cancelled={Cancelled})";
}
}
public class API
{
public static void Print(string text)
{
Console.WriteLine($"[API] {text}");
}
}
public class Program
{
public static string TestValue = "some initial test value";
static void Main(string[] args)
{
var evt = new GameEvent();
Console.WriteLine("[Console] " + evt.ToString());
Console.WriteLine("[Console] Loading dll...");
// var asm = Assembly.LoadFile(#"C:\Users\tinytengu\Desktop\SharpTest\SharpExternal\bin\Release\netcoreapp3.1\SharpExternal.dll");
var asm = Assembly.LoadFile(#"C:\Users\tinytengu\SharpExternal\SharpExternal.dll");
var classType = asm.GetType("SharpExternal.Class1");
Console.WriteLine("[Console] Invoking SharpExternal.Class1.Main method...");
var methodInfo = classType.GetMethod("Main", BindingFlags.Static | BindingFlags.Public);
methodInfo.Invoke(null, new object[] { evt });
Console.WriteLine("[Console] After changes: " + evt.ToString());
Console.WriteLine();
methodInfo = classType.GetMethod("ShowTestValue", BindingFlags.Static | BindingFlags.Public);
methodInfo.Invoke(null, null);
Console.ReadLine();
}
}
}
And a class library:
using System;
namespace SharpExternal
{
public class Class1
{
public static void Main(ref SharpConsole.GameEvent evt)
{
Console.WriteLine("[DLL] " + evt.ToString());
Console.WriteLine("[DLL] Cancelling an event");
evt.SetCancelled(true);
}
public static void ShowTestValue()
{
SharpConsole.API.Print(SharpConsole.Program.TestValue);
}
}
}
What is going on:
The console app creates GameEvent class instance
It injects the ExternalSharp.dll
ExternalSharp.Class1.Main gets called passing previously created GameEvent instance reference to it.
ExternalSharp changes GameEvent's Cancelled state and SharpConsole outputs an instance of a GameEvent that has been successfully modified from ExternalSharp
ExternalSharp's ShowTestValue gets called so it outputs a Console's TestValue field value.
The thing is, I can compile SharpExternal (which uses SharpConsole project as a dependency so it can use its classes. I can also compile SharpConsole and use its DLL file as a dependency, the result is the same) once and move its DLL file on the Desktop so it can't access any files, be recompiled and etc., i.e. in a completely empty folder. BUT I can change Console's TestValue at any moment, even from Console.ReadLine in runtime, then recompile only the Console app and the SharpExternal will output new value when the ShowTestValue method is called. I can add more static properties, methods, etc. before and after TestValue, change the file as I want, but unchanged from the first time SharpExternal.dll file which is still located on the Desktop manages to find TestValue (and other static fields, methods, ...) every time and output the correct value.
I'd like to know how this whole thing works, how ExternalSharp finds the correct TestValue address every time. I suppose it's because of the static modifier, but I haven't found any information beyond the fact that it allows type members to refer to the type itself, and not just to its instance, which I already knew.

Roslyn, how can I instantiate a class in a script during runtime and invoke methods of that class?

I understand how I can execute entire scripts using Roslyn in C# but what I now want to accomplish is to compile a class inside the script, instantiate it, parse it to an interface and then invoke methods that the compiled and instantiated class implements.
Does Roslyn expose such functionality? Can you someone please point me to such approach?
Thanks
I think you can do what you want for example like this:
namespace ConsoleApp2 {
class Program {
static void Main(string[] args) {
// create class and return its type from script
// reference current assembly to use interface defined below
var script = CSharpScript.Create(#"
public class Test : ConsoleApp2.IRunnable {
public void Run() {
System.Console.WriteLine(""test"");
}
}
return typeof(Test);
", ScriptOptions.Default.WithReferences(Assembly.GetExecutingAssembly()));
script.Compile();
// run and you get Type object for your fresh type
var testType = (Type) script.RunAsync().Result.ReturnValue;
// create and cast to interface
var runnable = (IRunnable)Activator.CreateInstance(testType);
// use
runnable.Run();
Console.ReadKey();
}
}
public interface IRunnable {
void Run();
}
}
Instead of returning type you created from script you can also use globals and return it that way:
namespace ConsoleApp2 {
class Program {
static void Main(string[] args) {
var script = CSharpScript.Create(#"
public class Test : ConsoleApp2.IRunnable {
public void Run() {
System.Console.WriteLine(""test"");
}
}
MyTypes.Add(typeof(Test).Name, typeof(Test));
", ScriptOptions.Default.WithReferences(Assembly.GetExecutingAssembly()), globalsType: typeof(ScriptGlobals));
script.Compile();
var globals = new ScriptGlobals();
script.RunAsync(globals).Wait();
var runnable = (IRunnable)Activator.CreateInstance(globals.MyTypes["Test"]);
runnable.Run();
Console.ReadKey();
}
}
public class ScriptGlobals {
public Dictionary<string, Type> MyTypes { get; } = new Dictionary<string, Type>();
}
public interface IRunnable {
void Run();
}
}
Edit to answer your comment.
what if I know the name and type of the class in the script? My
understanding is that script.Compile() adds the compiled assembly to
gac? Am I incorrect? If I then simply use
Activator.CreateInstance(typeofClass) would this not solve my problem
without even having to run the script
Compiled assembly is not added to gac - it is compiled and stored in memory, similar to how you can load assembly with Assembly.Load(someByteArray). Anyway, after you call Compile that assembly is loaded in current app domain so you can access your types without RunAsunc(). Problem is this assembly has cryptic name, for example: ℛ*fde34898-86d2-42e9-a786-e3c1e1befa78#1-0. To find it you can for example do this:
script.Compile();
var asmAfterCompile = AppDomain.CurrentDomain.GetAssemblies().Single(c =>
String.IsNullOrWhiteSpace(c.Location) && c.CodeBase.EndsWith("Microsoft.CodeAnalysis.Scripting.dll"));
But note this is not stable, because if you compile multiple scripts in your app domain (or even same script multiple times) - multiple such assemblies are generated, so it is hard to distinguish between them. If that is not a problem for you - you can use this way (but ensure that you properly test all this).
After you found generated assembly - problems are not over. All your script contents are compiled under wrapping class. I see its named "Submission#0" but I cannot guarantee it's always named like that. So suppose you have class Test in your script. It will be child class of that wrapper, so real type name will be "Submission#0+Test". So to get your type from generated assembly it's better to do this:
var testType = asmAfterCompile.GetTypes().Single(c => c.Name == "Test");
I consider this approach somewhat more fragile compared to previous, but if previous are not applicable for you - try this one.
Another alternative suggested in comments:
script.Compile();
var stream = new MemoryStream();
var emitResult = script.GetCompilation().Emit(stream);
if (emitResult.Success) {
var asm = Assembly.Load(stream.ToArray());
}
That way you create assembly yourself and so do not need to search it in current app domain.

Create and use an instance of an class who's class name is only known at runtime

I have a list of class names and methods that can only be read during runtime. Is it possible to create a class dynamically like that? I'm currently using C# 4.0.
It is a little unclear whether you want to define a type at runtime and define methods against it, or whether you want to create an instance of an already-written type, and call methods on it.
Fortunately both are possible.
The second scenario is more likely, so you'd want to look at reflection (below) - but note that there are performance penalties associate with this (and small things like "what arguments does the method take" become very important).
For the first scenario, you'd need to look at TypeBuilder, but that is much more complex. Another option would be CSharpCodeProvider and dynamic assembly loading, but again - not trivial by any stretch.
using System;
namespace MyNamespace {
public class Foo {
public void Bar() {
Console.WriteLine("Foo.Bar called");
}
}
}
class Program {
static void Main() {
string className = "MyNamespace.Foo, MyAssemblyName",
methodName = "Bar";
Type type = Type.GetType(className);
object obj = Activator.CreateInstance(type);
type.GetMethod(methodName).Invoke(obj, null);
}
}
To include parameters (comments) you pass an object[] instead of the null:
using System;
namespace MyNamespace {
public class Foo {
public void Bar(string value) {
Console.WriteLine("Foo.Bar called: " + value);
}
}
}
class Program {
static void Main() {
string className = "MyNamespace.Foo, MyAssemblyName",
methodName = "Bar";
Type type = Type.GetType(className);
object obj = Activator.CreateInstance(type);
object[] args = { "hello, world" };
type.GetMethod(methodName).Invoke(obj, args);
}
}
If you are doing this lots (for the same method) there is a way to improve performance via a typed delegate, but this doesn't gain you much for occasional calls.
You can use the IL emit functionality straight out of the .Net framework to accomplish this. You will need to learn IL in order to dynamically generate type information at runtime--this is not for the feint of heart.
Introduction to Creating Dynamic Types with System.Reflection.Emit
As I can't really answer that you are asking I will answer a number of question you might want to ask.
Can I create an instance of class and call its method where both class and method are specified at run time?
Sure. The simple way first. Use a if statements:
var className = "MyClass";
var methodName = "MyMethod";
if (className == typeof(MyClass).Name) {
var instance = new MyClass();
if (methodName == "MyMethod")
instance.MyMethod();
if (methodName == "MyOtherMethod")
instance.MyOtherMethod();
}
Alternatively, you can use Activator.CreateInstance to create an instance of a class for you.
var className = "MyClass";
var methodName = "MyMethod";
//Get a reference to the Assembly that has the desired class. Assume that all classes that we dynamically invoke are in the same assembly as MyClass.
var assembly = typeof(MyClass).Assembly;
//Find the type that we want to create
var type = assembly.GetTypes().FirstOrDefault(t=>t.Name == className);
if(type != null) {
//Create an instance of this type.
var instance = Activator.CreateInstance(type);
//Find the method and call it.
instance.GetType().GetMethod(methodName).Invoke(instance);
}
Can I generate a class at run time?
Yes you can but it's hard. If you are an experienced C# programmer, know a bit of C++ and assembly, you should be able to grock it. If not, don't bother.
Microsoft provides a library to emit Intermediate Language code called, surpose, IL.Emit. There are very few problems that warrant using this method, amongst those are mock object generation and some aspects of Dependency Injection. It is quite likely that your problem is better solved in another fashion.

Correct Way to Load Assembly, Find Class and Call Run() Method

Sample console program.
class Program
{
static void Main(string[] args)
{
// ... code to build dll ... not written yet ...
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
// don't know what or how to cast here
// looking for a better way to do next 3 lines
IRunnable r = assembly.CreateInstance("TestRunner");
if (r == null) throw new Exception("broke");
r.Run();
}
}
I want to dynamically build an assembly (.dll), and then load the assembly, instantiate a class, and call the Run() method of that class. Should I try casting the TestRunner class to something? Not sure how the types in one assembly (dynamic code) would know about my types in my (static assembly / shell app). Is it better to just use a few lines of reflection code to call Run() on just an object? What should that code look like?
UPDATE:
William Edmondson - see comment
Use an AppDomain
It is safer and more flexible to load the assembly into its own AppDomain first.
So instead of the answer given previously:
var asm = Assembly.LoadFile(#"C:\myDll.dll");
var type = asm.GetType("TestRunner");
var runnable = Activator.CreateInstance(type) as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
I would suggest the following (adapted from this answer to a related question):
var domain = AppDomain.CreateDomain("NewDomainName");
var t = typeof(TypeIWantToLoad);
var runnable = domain.CreateInstanceFromAndUnwrap(#"C:\myDll.dll", t.Name) as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
Now you can unload the assembly and have different security settings.
If you want even more flexibility and power for dynamic loading and unloading of assemblies, you should look at the Managed Add-ins Framework (i.e. the System.AddIn namespace). For more information, see this article on Add-ins and Extensibility on MSDN.
If you do not have access to the TestRunner type information in the calling assembly (it sounds like you may not), you can call the method like this:
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
Type type = assembly.GetType("TestRunner");
var obj = Activator.CreateInstance(type);
// Alternately you could get the MethodInfo for the TestRunner.Run method
type.InvokeMember("Run",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
null);
If you have access to the IRunnable interface type, you can cast your instance to that (rather than the TestRunner type, which is implemented in the dynamically created or loaded assembly, right?):
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
Type type = assembly.GetType("TestRunner");
IRunnable runnable = Activator.CreateInstance(type) as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();
I'm doing exactly what you're looking for in my rules engine, which uses CS-Script for dynamically compiling, loading, and running C#. It should be easily translatable into what you're looking for, and I'll give an example. First, the code (stripped-down):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using CSScriptLibrary;
namespace RulesEngine
{
/// <summary>
/// Make sure <typeparamref name="T"/> is an interface, not just any type of class.
///
/// Should be enforced by the compiler, but just in case it's not, here's your warning.
/// </summary>
/// <typeparam name="T"></typeparam>
public class RulesEngine<T> where T : class
{
public RulesEngine(string rulesScriptFileName, string classToInstantiate)
: this()
{
if (rulesScriptFileName == null) throw new ArgumentNullException("rulesScriptFileName");
if (classToInstantiate == null) throw new ArgumentNullException("classToInstantiate");
if (!File.Exists(rulesScriptFileName))
{
throw new FileNotFoundException("Unable to find rules script", rulesScriptFileName);
}
RulesScriptFileName = rulesScriptFileName;
ClassToInstantiate = classToInstantiate;
LoadRules();
}
public T #Interface;
public string RulesScriptFileName { get; private set; }
public string ClassToInstantiate { get; private set; }
public DateTime RulesLastModified { get; private set; }
private RulesEngine()
{
#Interface = null;
}
private void LoadRules()
{
if (!File.Exists(RulesScriptFileName))
{
throw new FileNotFoundException("Unable to find rules script", RulesScriptFileName);
}
FileInfo file = new FileInfo(RulesScriptFileName);
DateTime lastModified = file.LastWriteTime;
if (lastModified == RulesLastModified)
{
// No need to load the same rules twice.
return;
}
string rulesScript = File.ReadAllText(RulesScriptFileName);
Assembly compiledAssembly = CSScript.LoadCode(rulesScript, null, true);
#Interface = compiledAssembly.CreateInstance(ClassToInstantiate).AlignToInterface<T>();
RulesLastModified = lastModified;
}
}
}
This will take an interface of type T, compile a .cs file into an assembly, instantiate a class of a given type, and align that instantiated class to the T interface. Basically, you just have to make sure the instantiated class implements that interface. I use properties to setup and access everything, like so:
private RulesEngine<IRulesEngine> rulesEngine;
public RulesEngine<IRulesEngine> RulesEngine
{
get
{
if (null == rulesEngine)
{
string rulesPath = Path.Combine(Application.StartupPath, "Rules.cs");
rulesEngine = new RulesEngine<IRulesEngine>(rulesPath, typeof(Rules).FullName);
}
return rulesEngine;
}
}
public IRulesEngine RulesEngineInterface
{
get { return RulesEngine.Interface; }
}
For your example, you want to call Run(), so I'd make an interface that defines the Run() method, like this:
public interface ITestRunner
{
void Run();
}
Then make a class that implements it, like this:
public class TestRunner : ITestRunner
{
public void Run()
{
// implementation goes here
}
}
Change the name of RulesEngine to something like TestHarness, and set your properties:
private TestHarness<ITestRunner> testHarness;
public TestHarness<ITestRunner> TestHarness
{
get
{
if (null == testHarness)
{
string sourcePath = Path.Combine(Application.StartupPath, "TestRunner.cs");
testHarness = new TestHarness<ITestRunner>(sourcePath , typeof(TestRunner).FullName);
}
return testHarness;
}
}
public ITestRunner TestHarnessInterface
{
get { return TestHarness.Interface; }
}
Then, anywhere you want to call it, you can just run:
ITestRunner testRunner = TestHarnessInterface;
if (null != testRunner)
{
testRunner.Run();
}
It would probably work great for a plugin system, but my code as-is is limited to loading and running one file, since all of our rules are in one C# source file. I would think it'd be pretty easy to modify it to just pass in the type/source file for each one you wanted to run, though. You'd just have to move the code from the getter into a method that took those two parameters.
Also, use your IRunnable in place of ITestRunner.
You will need to use reflection to get the type "TestRunner". Use the Assembly.GetType method.
class Program
{
static void Main(string[] args)
{
Assembly assembly = Assembly.LoadFile(#"C:\dyn.dll");
Type type = assembly.GetType("TestRunner");
var obj = (TestRunner)Activator.CreateInstance(type);
obj.Run();
}
}
When you build your assembly, you can call AssemblyBuilder.SetEntryPoint, and then get it back from the Assembly.EntryPoint property to invoke it.
Keep in mind you'll want to use this signature, and note that it doesn't have to be named Main:
static void Run(string[] args)

C# and Reflection

I'm a brand-newbie to C#, albeit not programming, so please forgive me if I mix things up a bit -- it's entirely unintentional. I've written a fairly simple class called "API" that has several public properties (accessors/mutators). I've also written a testing console application that uses reflection to get an alphabetically list of names & types of each property in the class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using MyNamespace; // Contains the API class
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hi");
API api = new API(1234567890, "ABCDEFGHI");
Type type = api.GetType();
PropertyInfo[] props = type.GetProperties(BindingFlags.Public);
// Sort properties alphabetically by name.
Array.Sort(props, delegate(PropertyInfo p1, PropertyInfo p2) {
return p1.Name.CompareTo(p2.Name);
});
// Display a list of property names and types.
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
Console.WriteLine("{0} [type = {1}]", propertyInfo.Name, propertyInfo.PropertyType);
}
}
}
}
Now what I need is a method that loops through the properties and concats all the values together into a querystring. The problem is that I'd like to make this a function of the API class itself (if possible). I'm wondering if static constructors have something to do with solving this problem, but I've only been working with C# for a few days, and haven't been able to figure it out.
Any suggestions, ideas and/or code samples would be greatly appreciated!
This is unrelated to static constructors. You can do it with static methods:
class API {
public static void PrintAPI() {
Type type = typeof(API); // You don't need to create any instances.
// rest of the code goes here.
}
}
You can call it with:
API.PrintAPI();
You don't use any instances when you call static methods.
Update: To cache the result, you can either do it on first call or in an static initializer:
class API {
private static List<string> apiCache;
static API() {
// fill `apiCache` with reflection stuff.
}
public static void PrintAPI() {
// just print stuff from `apiCache`.
}
}

Categories

Resources