I have a need to embed referenced assemblies as resources in my own library. For this I have created a little sample solution with 3 projects in it.
The first is called First and has no dependencies. The second is called Second and is dependent on First. The third is OutProj and has a reference to Second.
I have found this article about the PreApplicationStartMethodAttribute. I have added
[assembly: PreApplicationStartMethod(typeof(SecondNs.Startup), "Start")]
to my test project's AssemblyInfo class (first line after includes). Next I have defined the class and method as such:
class Startup
{
public static void Start()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
var name = args.Name.Substring(0, args.Name.IndexOf(','));
byte[] block = null;
switch (name)
{
case "First":
block = Properties.Resources.First;
break;
default:
break;
}
Assembly a2 = Assembly.Load(block);
return a2;
}
}
Both Second and OutProj have this class defined, with a difference in the switch case (the original code didn't do the trick so I modified it).
My main issue is that the Start method doesn't get called. When I add the start method code to my Main method it does indeed get called, but I don't have a Main in my class library. Is this the right approach or is there a better way to do this?
Related
I have a .dll library, which I cannot modify, with classes which uses many static variables and singleton instances.
Now I need a second instance of all these classes and I need some solution which would isolate static variables between instances of some class without altering any other properties of the assembly.
Loading the same assembly second time doesn't actually load it again, but I found that reading it to byte array and then loading it, actually solves half of the problem:
lib.dll:
namespace lib
{
public class Class1 : ILib
{
private static int i;
public int DoSth()
{
return i++;
}
public string GetPath()
{
return typeof(Class1).Assembly.Location;
}
}
}
app.exe:
namespace test
{
public interface ILib
{
int DoSth();
string GetPath();
}
class Program
{
static void Main()
{
var assembly1 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance1 = (ILib)assembly1.CreateInstance("lib.Class1");
Console.WriteLine(instance1.GetPath());
Console.WriteLine(instance1.DoSth());
Console.WriteLine(instance1.DoSth());
var assembly2 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance2 = (ILib)assembly2.CreateInstance("lib.Class1");
Console.WriteLine(instance2.GetPath());
Console.WriteLine(instance2.DoSth());
Console.WriteLine(instance2.DoSth());
var assembly3 = AppDomain.CurrentDomain.Load(File.ReadAllBytes("lib.dll"));
var instance3 = (ILib)assembly3.CreateInstance("lib.Class1");
Console.WriteLine(instance3.GetPath());
Console.WriteLine(instance3.DoSth());
Console.WriteLine(instance3.DoSth());
Console.Read();
}
}
}
this returns:
C:\bin\lib.dll
0
1
C:\bin\lib.dll
2
3
0
1
Static variables got restarted but unfortunately the next problem is that assembly location which is used within the library is empty.
I would like to avoid loading the library to different AppDomain because it creates too many problems with cross domain code; some classes are not serializable.
I would like to avoid physically copying the library on disk.
I would like to avoid IL weaving and using Mono.Cecil or similar because it's an overkill.
Loading assembly into separate AppDomain or separate process are only sensible options you have. Either deal with cross-domain/cross-process communication or get version of library that does not have problems you trying to work around.
If you want to fix your load from bytes you'd need to read all articles around https://blogs.msdn.microsoft.com/suzcook/2003/09/19/loadfile-vs-loadfrom/.
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.
Is it possible to create a project in C# without a main method, and import another project that has one, and set the entry point to be that main method of the imported project?
The purpose of this is to provide a library complete with its main method and all startup code, requiring only a couple of "plugin" methods. This will minimize boiler-plate (in particular, start-up) code.
Abstract example:
Consider Project 1 with Program.cs:
namespace Project1 {
public class Program {
public static void Main() {
Console.WriteLine("All your Main are belong to us");
Plugin pluginClass = MagicallyGetInstanceOfPluginClassProbablyThroughInjection();
pluginClass.DoSomethingSpecificDependingOnPluginClassDefinition();
}
private Plugin MagicallyGetInstanceOfPluginClassProbablyThroughInjection(){
/*...*/
}
}
public interface Plugin {
void DoSomethingSpecificDependingOnPluginClassDefinition();
}
}
Now consider Project 2 with only class MyPlugin.cs:
namespace Project2 {
using Project1;
public class MyPlugin: Plugin {
public void DoSomethingSpecificDependingOnPluginClassDefinition() {
Console.WriteLine("I'm doing something specific!");
}
}
}
Things to point out:
Project 1 is just a library, possibly nuget'ed
It's Project 2 that imports Project 1, not the other way around
The MyPlugin.cs class above is the only class/file in the project (excluding manifests, app configs, etc)
Aim:
Project 2 should compile into an executable, running Project 1's Main function without writing any more code (no boiler-plate start-up/set-up code). There can then be Project 3, 4, 5, ... that all implement their Plugin-specific code, import Project 1 and run as independent instances.
Is this possible to do? Or do I still have to make a main method in each project that calls the imported project's start-up code? Many thanks in advance!
You could create a plugin container that scans the directory for assemblies and tries to load them. For this you would need a shared interface (interface known to your program and the plugins.
You could then add the DLLs into a defined plugin directory or you could reference the projects inside your main running project.
An example of the interface could be:
public interface IStandAlone
{
void Run();
}
And 1 or to simple implementations could be
public class Program1 : IStandAlone
{
public void Run()
{
Console.WriteLine("Program1");
}
}
public class Program2 : IStandAlone
{
public void Run()
{
Console.WriteLine("Program 2");
}
}
Then you would need to load the possible assemblies, either from the current assemblies (as is done in this example), or by scanning a directory for dlls that might have your type.
An example that scans the current assemblies for any implementations of the a definite type:
public class PluginContainer<T>
{
Type targetType = typeof(T);
public virtual IList<Type> GetMatchingTypes()
{
Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
IList<Type> items = new List<Type>();
if (currentAssemblies == null || currentAssemblies.Length == 0)
{
Console.WriteLine("No assemblies found!");
return items;
}
foreach (Assembly ass in currentAssemblies)
{
try
{
var types = ass.GetTypes();
foreach (var t in types)
{
if (t.IsInterface)
{
continue;
}
if (!(targetType.IsAssignableFrom(t)))
{
continue;
}
items.Add(t);
}
}
catch (ReflectionTypeLoadException rtle)
{
/* In case the loading failed, scan the types that it was able to load */
Console.WriteLine(rtle.Message);
if (rtle.Types != null)
{
foreach (var t in rtle.Types)
{
if (t.IsInterface)
{
continue;
}
if (!(targetType.IsAssignableFrom(t)))
{
continue;
}
items.Add(t);
}
}
}
catch (Exception ex)
{
/* General exception */
Console.WriteLine(ex.Message);
}
}
return items;
}
public IList<T> GetPlugins()
{
IList<Type> matchingTypes = GetMatchingTypes();
IList<T> items = new List<T>();
if (matchingTypes == null || matchingTypes.Count == 0)
{
Console.WriteLine("No matching types of {0} found", typeof(T).FullName);
return null;
}
foreach (Type type in matchingTypes)
{
try
{
T nObj = (T)Activator.CreateInstance(type);
items.Add(nObj);
}
catch (Exception ex)
{
Console.WriteLine("Error occured trying to run {0}\r\n{1}", type.FullName, ex.Message);
}
}
return items;
}
}
which can then be used inside a main method to scan for any available plugins, and to execute them:
static void Main(string[] args)
{
PluginContainer<IStandAlone> container = new PluginContainer<IStandAlone>();
var plugins = container.GetPlugins();
foreach (var plugin in plugins)
{
plugin.Run();
}
Console.ReadLine();
}
which eventually gives as an output:
Program1
Program 2
Please keep in mind, that this is a very basic example, and that a well thought out interface should be in place, that really only contains the basics, and might give some feedback to the program running the plugins (though this shouldn't be a requirement). Also offering a versions for plugins, maybe an update Url, and such things could be handy in case your plugins can be maintained or implemented by 3th party providers...
I believe the requirement for a start-up method is that it's signature needs to be public static void and it needs to have a single string[] parameter. It may also need to be named "Main", but I doubt it. If a method matches those requirements it should be available to pick as the start-up method in a project's properties.
However the start-up method is what's used to run a stand-alone executable program when it's launched. I believe what you are looking for is more of a plug-in architecture. You can create an attribute and tag your entry point method(s) with that attribute. Then, in your service, you would need to reflect over the classes in the plug-in assembly which you are loading and find methods marked with your custom attribute, and invoke the appropriate one.
Sorry if this sounds a bit vague but a "plugin architecture" is not a trivial topic.
An alternative would be to use the System.Diagnostics.Process.Start(string) method to just launch your "plug-in" as a stand-alone program.
I'm not really sure what you're asking for. Every C# project is either a .exe or a .dll. A .dll does not have a main method, but an .exe needs one. Here's the link describing what it should look like.
If you have many very similar applications then you can move all the common stuff in a .dll project and reference it in all the applications. Then you can call the methods from each .exe. You'll still have a Main() method in each .exe, but it will only contain one line which calls the common implementation.
Or you can do something like a plugin architecture, where you have one .exe and all the other applications are .dll projects, which are loaded and executed by the .exe as needed.
Six of one, half a dozen of the other, it's all the same in the end.
I'm struggling with AssenblyResolve event for a while now. I've searched stackoverflow and did other googling and tried all that I think was relevant. Here are the links being the closer to my problem (in my opinion) :
AssemblyResolve is not invoked and FileNotFoundException is thrown during serialization
Where to handle AssemblyResolve event in a class library?
I have a Bootstrapper class with to static method (I will remove the thread safe code that we have, just for the sake of clarity :
public static void Initialize()
{
AppDomain.CurrentDomain.AssemblyResolve += CustomResolve;
}
private static Assembly CustomResolve(object sender, ResolveEventArgs args)
{
// There is a lot code here but basicall what it does.
// Is determining which architecture the computer is running on and
// extract the correct embedded dll (x86 or x64). The code was based
// on milang on GitHub (https://github.com/milang/P4.net). And it's the same
// purpose we want to be able to load the x86 or x64 version of the perforce dll
// but this time with the officially Perforce supported p4api.net.
// Once the dll is extracted we assign it to the boostrapper
Bootstrapper._p4dnAssembly = Assembly.LoadFile(targetFileName);
// Make sure we can satisfy the requested reference with the embedded assembly (now extracted).
AssemblyName reference = new AssemblyName(args.Name);
if (AssemblyName.ReferenceMatchesDefinition(reference, Bootstrapper._p4dnAssembly.GetName()))
{
return Bootstrapper._p4dnAssembly;
}
}
I was able to make the code work if the I have simple class with a main method and static constructor. The static constructor is simply calling the Boostrapper.Initialize() method.
After that, I could use my library and it was working as expected :
public static class Test
{
static Test()
{
Bootstrapper.Initialize();
}
public static void Main()
{
// Using the library here is working fine. The AssemblyResolve event was
// fired (confirmed by a breakpoint in Visual Studio)
}
}
The problem I have is if there is at least one layer of dependency. Basically the code stays the same but this time my the code of the library is inside another library :
public static class Test
{
static Test()
{
Bootstrapper.Initialize();
}
public static void Main()
{
Class1 myClass = new Class1();
// The following line is using the code of the extracted library, but
// The AssemblyResolve event is not fired (or fired before I register the
// callback) and therefore the library is not found : result
// BadImageFormatException() error could not load libary because one
myClass.Connect();
}
}
Sounds like #2 of the links I've previously stated explain what I'm seeing but it does not work. Visual Studio break point on the AssemblyResove callback is never being hit.
Any idea of what's going on?
Francis
I know it's been a while since this question was asked and answered, but I wanted to add my take on the issue anyway (since I just wasted a few hours over this, maybe thanks to this someone else wouldn't have to)
The problem is basically the fact, that the application is trying to resolve all assemblies needed to execute the method at the beginning of that method:
static void main(string[] args)
{
// <-- here the app tries to resolve MyAssembly
// and as MyAssembly.Class1 is not found, the app crashes
// this next line is never called:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
// class contained in an assemnly that we need to resolve
MyAssembly.Class1 myClass = new MyAssembly.Class1();
}
That's why the above will crash: the ResolveAssembly event handler will never be called because it was never hooked up.
And that's also why the below solution works (as posted by the OP):
static void main(string[] args)
{
Initialize();
RealMain();
}
static void Initialize()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
}
static void RealMain()
{
// <-- here the app tries to resolve MyAssembly
// class contained in an assemnly that we need to resolve
MyAssembly.Class1 myClass = new MyAssembly.Class1();
// and everything is OK
}
Someone did answer but the answer has been deleted. So I can't mark it as answered.
Basically the fact the code needs not to be outside the "main" method is working.
Starting fresh from a new project, solve the issue so I guess I had some problems with the dll (probably x86 dll in x64 folder or vice-versa)
static void main(string[] args)
{
Boostrapper.Initialize();
RealMain();
}
static void RealMain()
{
Class1 myClass = new Class1();
myClass.Connect();
}
I am trying to use the CurrentDomain.AssemblyResolve event to load a DLL that is marked as an Embedded Resource. My problem, specifically, comes from the fact that I am trying to use the assembly as a subclass, like so:
#define BROKEN
using System;
using System.Reflection;
using TestCompanyInc;
namespace TestConsole
{
#if BROKEN
// This is how I NEED to use it
class Program : SubClass
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
class Program
#endif
{
static int Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
string resourceName = Assembly.GetExecutingAssembly()
.GetName().Name
+ "." + new AssemblyName(eventArgs.Name).Name + ".dll";
Console.WriteLine("About to lookup {0}", resourceName);
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Program p = new Program(args);
return p.Run();
}
public Program(string[] args)
{
}
public int Run()
{
#if BROKEN
// This is how I NEED to use it
Console.WriteLine(TestProperty);
#else
// This is only here as a test to make sure I wired
// CurrentDomain.AssemblyResolve correctly
SubClass sc = new SubClass();
Console.WriteLine(sc.TestProperty);
#endif
Console.ReadKey();
return 0;
}
}
}
The test class SubClass is defined as:
namespace TestCompanyInc
{
public class SubClass
{
public SubClass()
{
TestProperty = "Init'd";
}
public string TestProperty { get; set; }
}
}
If the first line #define BROKEN is left uncommented, then the CurrentDomain.AssemblyResolve event will never fire and System.IO.FileNotFoundException is thrown and I am told that SubClass can not be found. If the first line is removed or commented out, then it will fire the event (but I can't use it this way).
I have also tried moving Main into its own class instead of having the same class create an instance of itself, but I get the exact same exception.
So, how do I get this event wired up correctly so it will load this assembly under these conditions?
Compiled in VS 2010 .NET 4, if that makes a difference to anyone. Also, for anyone trying to recreate this. SubClass is in its own project. Add SubClass as a Reference to TestConsole and mark it as Copy Local = False. I have read, somewhere, that this can not be a Project Reference, but a direct reference to the DLL. Then, add the DLL file to the TestConsole project and mark it as an Embedded Resource, not the default of Content.
Think about load-order... In order to JIT and invoke Main, it must understand Program. It can't understand Program without loading the base-class, which needs special handling. The event doesn't fire because it hasn't registered yet (because Main hasn't started).
That cannot work. The only way you can do this is to have an entry-point that doesn't depend on anything else. Note that JIT is done before the method starts, so the Main also can't involve anything that isn't known. For example, you might do:
class Loader {
static void Main()
{
// not shown: register assemy-load here
MainCore();
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void MainCore()
{ // your class as shown is Program
Program.Init();
}
}
Note we need 2 methods above since it can't JIT Main unless it can fully resolve Program. With the above, the event should fire just before MainCore() is invoked (I.e. During JIT for MainCore).