how to use MarshalByRefObject to call class in different app domain - c#

I am trying to implement a version of example 1 from here http://msdn.microsoft.com/en-us/library/System.MarshalByRefObject(v=vs.110).aspx into my code.
My aim is to have a class with some methods then load that class into a different appdomain and call its method.
so far I have:
public class diffDomain : MarshalByRefObject
{
public int getNumber()
{
return 5;
}
}
internal static class JITCompiler
{
internal static wantNumber()
{
AppDomain domain = AppDomain.CreateDomain("MyDomain");
var newSearch = (diffDomain)domain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
"diffDomain");
}
}
I get an error on the Var newSearch line:
Could not load type 'diffDomain' from assembly 'SVM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Your assembly/namespace could be incorrect. To avoid such errors try this:
var newSearch = (diffDomain)domain.CreateInstanceAndUnwrap(
typeof(diffDomain).Assembly.FullName,
typeof(diffDomain).FullName);

What you put in your question isn't your real code, as it has an obvious syntax error.
What you put in your question also doesn't demonstrate the issue you're having, because you excluded relevant information.
What I think you've done is put your classes in a namespace. CreateInstanceAndUnwrap expects a fully qualified name. The example you linked to puts the class in the global namespace, so the unqualified name and qualified names are the same. They probably aren't in what you're trying.

Related

Why usage of dynamic throws exception in runtime?

I have an external dll I'm loading into my appdomain during runtime.
I'm creating an instance of a class from that assembly into a local dynamic variable.
As far as I understood the usage of dynamic in C#, I can simply call a method of it, which will be resolved at run time...
Using this approach, the following code gets me a runtime "'object' does not contain a definition for 'Get'" exception.
I'll try to illustrate the structure as I can't expose the actual code.
External dll name: a.b.c
namespace Ext
{
public static class FactoryCreator
{
public static ProxyFactory CreateFactory()
{
return new ProxyFactory();
}
}
public interface FactoryIfc
{
Proxy Get();
}
internal class ProxyFactory: FactoryIfc
{
private Proxy proxy;
public Proxy Get()
{
if (this.proxy == null)
this.proxy = <a method to create a proxy>
return this.proxy;
}
}
}
I'm using the following code
var assembly = "a.b.c, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<key>,processorArchitecture=MSIL";
var instName = "Ext.FactoryCreator";
dynamic factoryCreator = AppDomain.CurrentDomain.Load(assembly).GetType(instName).GetMethod("CreateFactory").Invoke(null, new object[0]);
dynamic proxy = factoryCreator.Get();
I understand that for FactoryCreator dynamic variable, I need to get the Type and invoke the static method of it, but.. as I said, it is throwing an exception "'object' does not contains a definition for 'Get'" - at the factory.Get() statement - while I would expect dynamic factory to be resolve automatically to the object and service the Get() call.
Observing the situation under a debug session, I can clearly see the Get method using factory.GetType().GetMethods() in the quickwatch window.
Can you explain what is happening?
Must I use factory.GetType().GetMethod("Get") followed by an Invoke? I thought the power of dynamic should work this out automatically in runtime...

Load same assembly second time with clean static variables

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

expose a referenced type (class) without need for additional reference

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.

Weird compile-time error on Select() and ToList() LINQ methods

I have a few simple lines of code in a WPF project which give me compilation errors.
var resourceNames = new List<string> { "cmbItem1", "cmbItem2", "cmbItem3", "cmbItem4" };
var comboBoxItems = resourceNames.Select(id => (string)FindResource(id)).ToList();
// other code
The compilation error text is
Error 2 The type
'System.Windows.Forms.Control' is defined in an assembly that is not
referenced. You must add a reference to assembly
'System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089'.
Why have I reference that assembly? I don't use any type from System.Windows.Forms.Control!
If I rewrite the code to make static methods invocations instead of extension methods invocations, it works fine:
var resourceNames = new List<string> { "cmbItem1", "cmbItem2", "cmbItem3", "cmbItem4" };
var comboBoxItems = Enumerable.Select(resourceNames, id => (string)FindResource(id));
comboBoxItems = Enumerable.ToList(comboBoxItems);
// other code
Why is it so? What am I doing wrong?
UPD1:
UPD2: THE ANSWER
I and my colleague have investigated the project and found that the reason of the problem. Here are several facts about our visual studio solution:
The problematic code resides in project called Flyer2. That project has a reference to another project called Global.
The project Global has several classes which provide global accessible extension methods.
One of the extension method has a restriction for a generic type in where clause. The restriction says that the generic type must be an descendant of System.Windows.Control... For some reason existence of a such method produces the compile-time error I've described...
Here is the code of the extension method and the class defining it:
using System.Windows.Forms;
namespace Global
{
public static class ControlExtensions
{
// If I remove the where-clause, the code problem disappears!
public static T FindParentByType<T>(this Control parentControl) where T : Control
{
var currentControl = parentControl != null ? parentControl.Parent : null;
while (currentControl != null)
{
if (currentControl is T)
return (T)currentControl;
currentControl = currentControl.Parent;
}
return null;
}
}
}

instantiate a class implementing a generic interface using reflection

I have the following in a business logic assembly:
public class BusinessEntity
{
...
}
public class Customer : BusinessEntity
{
...
}
public interface IEntityManager <T> where T : BusinessEntity
{
T SaveData(T oData);
}
public CustomerEntityManager : IEntityManager <Customer>
{
Customer SaveData(Customer o)
{
...
}
}
I am forced to load the above assembly (due to a couple of obvious reasons) in my current project through reflection and instantiate CustomersEntityManager. Imagine that I am writing a method as follows:
public class EntityFactory
{
public static IEntityManager<BusinessEntity> GetManagerInstance(string EntityName)
{
var asm = GetAssembly(); // imagine that I loaded the assembly somehow
EntityName = "Customer"; // just imagine
object o;
// DO NOT KNOW WHAT TO WRITE HERE.
return o as IEntityManager<BusinessEntity>; // this needs to be an instance of CustomerEntityManager.
}
}
I have the option to modify business assembly. But the instance creation needs to be in my current project and I have to load the business assembly using reflection. All the data types will be known only at run-time.
I may be missing some fundamental things or probably doing wrong coding. Please help me out on this.
UPDATE:
Followed "driss" suggestion, like following:
string fullTypeName = "Your.Namespace." + EntityName + "EntityManager";
object o = Activator.CreateInstance(asm.FullName, fullTypeName);
Looks like it created the instance. However, it ended up with an error:
Cannot cast 'o' (which has an actual type of 'CustomerEntityManager') to 'IEntityManager'
when the following statement is getting executed:
return o as IEntityManager<BusinessEntity>
Thanks
You need to construct the full type name somehow, so that you can get the Type instance representing the type. You might decide that the type name relies on a convention, such that you could find the full type name as:
string fullTypeName = "Your.Namespace." + EntityName + "EntityManager";
object o = Activator.CreateInstance(asm.FullName, fullTypeName);
Then it is just a matter of calling Activator.CreateInstance, as you see.
However, I would highly recommend you looking into using an IoC framework for solving this problem.
Re: your comment:
You can't cast CustomerEntityManager to IEntityManager, because that is not what it implements - it only implements IEntityManager. If the cast was allowed, type safety would be broken (you could pass in a BusinessEntity, when the implementation clearly expects a Customer, or, that is at least what the contract says. (Co/contra variance can't save you here because T goes both in and out of IEntityManager).
Forget about using low-level reflection at your own, a lot of not very convenient work. Use an IoC framework if you can, i.e. StructureMap. With StructureMap you'll just need to create a Registry that knows all the dependencies (such as CustomersEntityManager is our implementation for IEntityManager<Customer>). It looks more less like that:
For<IEntityManager<Customer>>().Use<CustomersEntityManager>()
And now if you ask your StructureMap container for an implementation of IEntityManager<Customer>, you'll get CustomersEntityManager:
ObjectFactory.GetInstance<IEntityManager<Customer>>(); // will return instance of CustomersEntityManager
If you don't know the requested type at compile time, you can ask for the entity manager using plain Type instance:
string entityName = "Customer";
Type entityType = Type.GetType(entityType);
Type requestedType = typeof(IEntityManager<>).MakeGenericType(new[] { entityType });
ObjectFactory.GetInstance(requestedType); // will also return CustomersEntityManager instance
Registry can be defined in your assembly, without touching the business assembly.
Checkout Activator.CreateInstance()
Object o = Activator.CreateInstance (asm.FullName, EntityName );
will give you an instance of the Customer. I'm not sure how you would go from Customer to CustomerEntity but I'm sure you can work that part out.

Categories

Resources