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/.
Related
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 am experiencing a memory leak in context with AppDomains. I've stripped it down to the following:
I got 3 projects, two library projects and a console project: Shared, DynamicallyLoadable and RemotingTimeoutPrototype (the console program). Shared contains interfaces used by both DynamicallyLoadable and RemotingTimeoutPrototype. Both reference Shared at compile-time. There are no other compile-time references between any of the projects.
Shared contains this:
public interface IHostService
{
string GetStuff();
}
public interface IRemoteClass
{
IHostService Alpha { get; set; }
string CallHostServices();
}
DynamicallyLoaded contains only a single type:
public class RemoteClass : MarshalByRefObject, IRemoteClass
{
public IHostService Alpha { get; set; }
public string CallHostServices()
{
Console.WriteLine("Domain {0}, RemoteClass.CallHostServices():", AppDomain.CurrentDomain.Id);
return Alpha.GetStuff();
}
}
The console project contains an implementation of IHostService:
public class Alpha : MarshalByRefObject, IHostService
{
readonly byte[] mBuffer = new byte[100*1024*1024];
public Alpha()
{
for (var i = 0; i < mBuffer.Length; ++i)
mBuffer[i] = (byte) (i%256);
}
public string GetStuff()
{
return "Alpha";
}
}
Program.Main consists of this:
while (true)
{
var otherDomain = AppDomain.CreateDomain("OtherDomain");
var proxy =
(IRemoteClass)
otherDomain.CreateInstanceFromAndUnwrap("../../../DynamicallyLoadable/bin/debug/DynamicallyLoadable.dll",
"DynamicallyLoadable.RemoteClass");
var alpha = new Alpha();
proxy.Alpha = alpha;
Console.WriteLine(proxy.CallHostServices());
Thread.Sleep(TimeSpan.FromSeconds(2));
AppDomain.Unload(otherDomain);
RemotingServices.Disconnect(alpha); // this was just an attempt, doesn't change a thing whether it's there or not
GC.Collect(); // same here, this shouldn't really be necessary, I just tried it out of despair
}
Now when I let this run for a while, memory consumption increases constantly and eventually I hit an OutOfMemoryException.
I would expect that if the domain holding the proxy is unloaded, then the proxy is unloaded, too, and there are no references to the concrete Alpha anymore, so this would be collected. But obviously it is not.
Note that I also checked that the domain is really being unloaded by referencing mscoree and enumerating the loaded domains with code along the lines of:
var runtimeHost = new CorRuntimeHost();
runtimeHost.EnumDomains(out handle);
// etc.
Also, if I attach a handler to otherDomain.DomainUnload(), this handler is called just fine.
Can anyone shed some light on this, please?
It might be a typical problem of blocked finalization thread (as you have while-loop in, probably, STA thread and never give control to another threads explicitly). Even though you unload/dispose the domain it might be in the memory because it is not finalised. Read more here: http://alexatnet.com/articles/memory-leaks-in-net-applications - specifically the section "Blocked Finalization Thread" (I'm the author)
I have a layered system of .dlls between my application, where the lowest level has a class that provides certain functionality - an instance of this class can be received through a GetClass() function and then I can access its properties (basically, a collection of information of changing objects).
Now I noticed that when I want to access that information from the next higher level .dll, the compiler complains that I do not have the lower level .dll referenced (the one defining the class) - which actually I would want to avoid, to have a nice layered structure in my architecture.
How to get around this? Can I re-expose the referenced type? Do I really have to write a wrapper of my own, if I want exactly the same functionality? Or do I even need to reference the low level .dll again?
DLL 1:
class myClass;
myClass GetMyClass();
DLL 2:
myClass GetMyClass();
EXE:
How to access result from calling GetMyClass (DLL 2) without referencing DLL 1?
You need to separate all the common classes you use across all your layers into a new dll, then reference this dll on every project.
Try to use interfaces so you can work over the contract (the functionality) instead of the concrete implementation. It will help you to avoid unnecessary references.
// common dll
public interface IMyClass
{
string MyData { get; set; }
IMyClass GetMyClass();
}
// dll1
public class myClass : IMyClass
{
public string MyData { get; set; }
public IMyClass GetMyClass() { return new myClass() { MyData = "abc" }; }
}
// dll2
public class myClass2
{
public IMyClass GetMyClass()
{
var c1 = new myClass();
var c2 = c1.GetMyClass();
return c2;
}
}
// exe (references common and dll2)
public class Program
{
public static void Main(string[] args)
{
var c1 = new myClass2();
IMyClass c2 = c1.GetMyClass();
Console.Writeline(c2.MyData);
}
}
Seems no way to achieve this, if myClass is defined in dll1, since objects of type myClass may be instantiated at runtime. To avoid this, you need to change the return type of GetMyClass() in dll2 to return something defined in dll2. It can be a class quite similar to myClass and having the same properties (you can even use tools like AutoMapper to easily convert between objects), but it definitely should be in dll2. Something like:
// dll1
class myClass
{
...
}
myClass GetMyClass()
{
...
}
// dll2
class myClass2
{
public myClass2(myClass c)
{
// instantiate myClass2 with values from myClass
}
}
myClass2 GetMyClass()
{
// somehow get myClass and convert it to myClass2 here
}
We do something similar to this in our local code. You can load the assembly at runtime, scan the types it contains using reflection, and again using reflection call functions and instantiate types from that dll, without ever referencing it directly in the project.
some of the key functions you will need are:
Assembly.LoadFrom(path); //get the assembly as a local object
Activator.CreateInstance(type); //create an instance of a type
Assembly.GetType(string);//fetch a type by name from the assembly
Once you have the type, basic reflection will give you pretty much every other piece you need.
Here is the snippet from my local code:
asm = Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, filePath));
Type[] types = asm.GetTypes();
for (var x = 0; x < types.Length; x++)
{
var interfaces = types[x].GetInterfaces();
for (var y = 0; y < interfaces.Length; y++)
{
if (interfaces[y].Name.Equals("MyTypeName"))
{
isValidmod = true;
var p = (IMyType)Activator.CreateInstance(types[x]);
//Other stuff
}
}
Also note: this is pretty old code now. It has been neither reviewed nor refactored in years, so its essentially modern as of .NET 1.1, BUT: It illustrates the point. How to load a type from a remote assembly that is NOT locally referenced.
Additionally, this is part of an engine that loads some 50 of these, given a rigid folder structure, which is why its so generic looking. Take what you need from it.
The caller must have a reference to the class in DLL1 to know what type it is accessing. So yes you need to reference the first dll in the exe. Since GetMyClass() returns a type in DLL1 the type needs to be exposed in the exe, therefore dll1 must be referenced.
I go with Nick using any Ioc framework like spring.net or microsoft unity. to get the idea properly go through http://martinfowler.com/articles/injection.html
One solution here is to provide a 4th DLL that contains interfaces for your classes. You would reference this in all 3 of your layers, and return these interfaces instead of your classes.
This should give you a good idea of what I mean:
// DLL1
class ClassInDLL1 : IClassInDLL1
{
}
// DLL2
class ClassInDLL2
{
public IClassInDLL1 GetClassInDLL1()
{
return new ClassInDLL1();
}
}
// DLL3
class ClassInDLL3
{
public void DoSomething()
{
var dll2 = new ClassInDLL2();
var dll1 = dll2.GetClassInDLL1(); // dll1 variable is of type IClassInDLL1
// do stuff with dll1
}
}
// interface DLL
interface IClassInDLL1
{
}
I'll be honest though, layering your architecture like this is usually not an awesome idea unless your project is really large. I find that artificially making assembly splits like this ahead of time can cause you unnecessary pain, not to mention the fact that you end up with 3-4 assemblies for a medium or small project that might only need 1.
I have been trying to teach myself MEF, starting with this tutorial:
http://blogs.msdn.com/b/brada/archive/2008/09/29/simple-introduction-to-composite-applications-with-the-managed-extensions-framework.aspx
There are some differences from the way MEF works now compared to the way it seems to work in this tutorial. One difference is the CompositionBatch object; however, I think I understand the changes that were made.
One difference I can't seem to understand, though, is that whereas the tutorial says I should be able to handle 0/1/multiple imports by changing the return type of a property, I can't make this work in practice. Below I will paste the code that is giving me an error; can anyone enlighten me as to why this doesn't work and what I should do instead?
I will eventually be using MEF to create a plugin-based application that will have different functionality added at runtime by dropping different .dll files that implement a certain interface into a directory. I think I'll be using the DirectoryCatalog for that, but I think I need to understand this hurdle first.
namespace MessinWithMef
{
class Program
{
[Import]
public IEnumerable<string> Message { get; set; }
public void Run()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var batch = new CompositionBatch();
batch.AddPart(this);
var container = new CompositionContainer(catalog);
container.Compose(batch);
foreach (var s in Message)
{
Console.WriteLine(s);
}
Console.ReadKey();
}
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
}
public class SimpleHello
{
[Export]
public string Message
{
get
{
return "Hello world!";
}
}
}
public class ExtraHello
{
[Export]
public string OtherMessage
{
get
{
return "Hi there!";
}
}
}
}
Here's the text of the error:
The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) No valid exports were found that match the constraint '((exportDefinition.ContractName == "System.Collections.Generic.IEnumerable(System.String)") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "System.Collections.Generic.IEnumerable(System.String)".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.
Resulting in: Cannot set import 'MessinWithMef.Program.Message (ContractName="System.Collections.Generic.IEnumerable(System.String)")' on part 'MessinWithMef.Program'.
Element: MessinWithMef.Program.Message (ContractName="System.Collections.Generic.IEnumerable(System.String)") --> MessinWithMef.Program
You have to use [ImportMany] if you want to resolve multiple matching Exports.
Note that, in a Plugin type of scenario, you'll probably want to use ExportMetadata and then decide which of the Plugins you actually want to instantiate. You would then do something like:
[ImportMany]
IEnumerable<Lazy<IPlugin, IPluginMetadata>> _possiblePlugins;
Now your code can enumerate the possible plugins, examine the metadata, and then decide whether or not to instantiate each Lazy import.