Running plugin in a different AppDomain C# - c#

I'm having difficulties trying to run a .dll in a new AppDomain. My object is always of type System.MarshalByRefObject, so I cannot get the methods from the plugin.
What I have right now, is a plugin, that implements an interface and extending a MarshalByRefObject, looking like this:
public interface IPlugin
{
string Name { get; }
string Description { get; }
string Author { get; }
void Execute();
}
Then I have my plugin implemented like this:
[Serializable]
public class IPPlugin : MarshalByRefObject, IPlugin
{
public string Author
{
get
{
return "John John";
}
}
public string Description
{
get
{
return "description";
}
}
public string Name
{
get
{
return "name";
}
}
public void Execute()
{
//do stuff here
}
}
So I built the plugin, got the dll, placed it in a folder and now in my project I'm trying to load it like this:
AppDomain domain = AppDomain.CreateDomain("PluginDomain");
Object obj = domain.CreateInstanceFromAndUnwrap(path + "\\" + plugins[option].getAssemblyName(), plugins[option].getTypeName());
Console.WriteLine(obj.GetType());
if (RemotingServices.IsTransparentProxy(obj))
{
Type type = obj.GetType();
MethodInfo Execute = type.GetMethod("Execute");
Execute.Invoke(obj, null); //crashes here
}
But it crashes on Execute.Invoke(...), because it doesn't know the method Execute, since the object is of wrong type.
Error message is:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.

Related

How can I force-cast a data to the generics specified in the method constraint?

I have the following data class and VM class:
public interface IData
{
string Name
{
get;
}
}
public class DataPartial: IData
{
public DataPartial()
{
}
public string Name => "Data partial";
}
public class DataFull : IData
{
public string Name => "Data full";
public DataFull()
{
}
}
public interface IVM
{
IData Data { get; }
}
public interface IVM_partial: IVM
{
new DataPartial Data { get; }
}
public class VM_Partial : IVM_partial
{
public VM_Partial()
{
Data = new DataPartial();
}
public DataPartial Data { get; set; }
IData IVM.Data => Data;
}
public interface IVM_Total:IVM_partial
{
new DataFull Data { get; }
}
public class VM_Total : IVM_Total
{
public VM_Total(IVM_partial dataA)
{
Data = new DataFull();
DataA_interface = dataA;
}
public IVM_partial DataA_interface { get; }
public DataFull Data { get; private set; }
DataPartial IVM_partial.Data => DataA_interface.Data;
IData IVM.Data => Data;
}
public static class RunVM<T, VM>
where T: class, IData
where VM :class, IVM
{
public static T RunMe(VM hi)
{
var vmA = (hi as VM); //how to force-cast this to the VM type??!!
return (T)vmA.Data;
}
}
class Program
{
static void Main(string[] args)
{
VM_Partial partialData = new VM_Partial();
var VMClass = new VM_Total(partialData);
RunVM<DataFull, IVM_Total>.RunMe(VMClass);
RunVM<DataPartial, IVM_partial>.RunMe(VMClass); //here it throws exception because I can't force cast the IVM to IVM_partial
}
}
At the method RunVM<DataPartial, IVM_partial>.RunMe(VMClass);, I want it to return me the DataPartial object, which I know it's there in the object VMClass, but I cannot get it done.
I will get an InvalidCastException when I am at the RunMe method, because the parameter hi is always VMClass, and I can never get it to behave like IVM_partial class. In other words, I can't cast hi to a more basic interface IVM_partial.
How to cast hi to a more basic interface IVM_partial? Is it possible at all, and if not, why not?
It's not the cast that's the problem - it's that you expect the compiler (or runtime) to pick up on the fact that the cast is to a type that declares a new Data property.
This line in RunMe:
return (T)vmA.Data;
... will always use the Data property declared by IVM, because that's the only property the compiler knows about when it's compiling that method. It doesn't matter that you're casting to another interface that contains a new Data property... the cast is about an execution-time check; it doesn't change which Data property the method uses.
It's unclear to me exactly what you're trying to achieve here, but I strongly suspect that you'll need to change tack significantly - maybe by adding another generic type parameter into the mix, maybe by using polymorphism more, or maybe changing the design more radically.

could not load assemly error when try to load plugins in c#

I want to create a Plugin architecture so I created the following interface
public interface IPlug
{
string Id { get; }
string Name { get; }
byte IsOn { get; }
bool Execute();
}
Now I reference the above interface to another class library project.
namespace PlugANameSpace
{
public class PlugA : IPlug
{
private byte _isOn;
public string Id
{
get {return "6666"; }
}
public byte IsOn
{
get { return _isOn; }
}
public string Name
{
get { return "PlugA"; }
}
public PlugA()
{
LoadFromRegistry();
}
public bool Execute()
{
// do some thing that returns true for success or false for error
}
private void LoadFromRegistry()
{
//register in registry
}
}
}
The above class library is copied into the main assembly file and stored in a folder "Plugins". Then I tried to load the plugin with the following code.
IPlug plug= Activator.CreateInstanceFrom(file, typeof(IPlug).FullName) as IPlug;
file is dll file got from Directory.GetFiles method.
When I tried to create instance, it throws error " Could not load type 'IPlug ' from assembly 'PlugA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. "
what I am doing wrong.?
You need to specify the name of the type in the PlugA assembly.
IPlug plug = Activator.CreateInstanceFrom(file, "PlugANameSpace.PlugA") as IPlug;
Edit: If you want to load a plugin without knowing the name of the type:
var assemblyName = AssemblyName.GetAssemblyName(file);
var assembly = Assembly.Load(assemblyName);
var pluginType = assembly.GetTypes().FirstOrDefault(t => typeof(IPlug).IsAssignableFrom(t));
IPlug plug = Activator.CreateInstance(pluginType) as IPlug;

How to access proxied object using impromptu-interface

How can I get access to the Duck Typed proxied object when using impromptu-interface. consider my code that illustrates my example where I get a InvalidCastException when I try to cast my Duck Typed Object to the proxied Object:
using System;
using ImpromptuInterface;
namespace ConsoleApplication1
{
public class Duck
{
public string Says { get; set; }
public int GetNumberOfQuacksPerMinute()
{
return 42;
}
}
public interface IPondBird
{
string Says { get; set; }
}
class Program
{
static void Main(string[] args)
{
// Duck says Quack! Quack!! Quack!!!
var thing = new Duck { Says = "Quack! Quack!! Quack!!!" };
IPondBird myInterface = Impromptu.ActLike(thing);
// ...
// Later on, I want to get access to a proxied object, but I
// get a InvalidCastException here
Duck proxiedObject = (Duck) myInterface;
Console.WriteLine("Duck # quacks per minute: "
+ proxiedObject.GetNumberOfQuacksPerMinute());
}
}
}
Exception is as follows:
An unhandled exception of type 'System.InvalidCastException' occurred
in ConsoleApplication1.exe
Additional information: Unable to cast object of type
'ActLike_IPondBird_c7dd53902ec74f01a3844d4789244ea3' to type
'ConsoleApplication1.Duck'.
You can't. You can think about line
IPondBird myInterface = Impromptu.ActLike(thing);
As something like
public class Wrapper : IPondBird
{
public Wrapper(Duck duck) { ... }
}
IPondBird myInterface = new Wrapper(thing);
That being said you can make the reference to native object part of the contract itself - like:
public interface IPondBird
{
string Says { get; set; }
object NativeObject { get; }
}
public class Duck
{
public string Says { get; set; }
public int GetNumberOfQuacksPerMinute()
{
return 42;
}
public object NativeObject { get { return this; } }
}
IPondBird myInterface = Impromptu.ActLike(thing);
var duck = (Duck)myInterface.NativeObject;
When you use impromptu interface, the generated proxy always has an explicit interface implementation for IActLikeProxy.
IPondBird myInterface = Impromptu.ActLike(thing);
var duck = (Duck)((IActLikeProxy)myInterface).Original;

Cannot access public methods through dll

I've a function QMain() whose return type is object.
public class QMain
{
public object objQ(string str)
{
if (str.ToUpper() == "A")
{
clsA objA = new clsA();
return objA;
}
else if (str.ToUpper() == "B")
{
clsB objB = new clsB();
return objB;
}
else
return "";
}
}
Following is clsA:
public class clsA
{
public string strMessage { get; private set; }
public static string staticField;
public bool cantAccessThisFn(string str)
{...}
}
Both of the above classes are in same project which is a class library. I've created another console application wherein I've included the above project's dll. Now, I'm doing:
QMain obj=new QMain();
object A=obj.objQ("A");
I can get strMessage, staticField but not cantAccessThisFn. If I directly make an object of clsA, I'm able to get cantAccessThisFn. Is there any way to get access to this function from obj (object of class QMain)?
I get the following error:
'object' does not contain a definition for 'cantAccessThisFn' and no extension method 'cantAccessThisFn' accepting a first argument of
type 'object' could be found (are you missing a using directive or an
assembly reference?)
The problem is your objQ method returns an object. You haven't defined any (extension) methods on object, so cantAccessThisFn definitely can't be accessed.
What you should do is this: create an interface with all methods you want to share between the two classes, and don't return object, but return IYourInterfaceName. Then you can access those methods and properties defined on the interface.
Something like this:
public class clsA : IYourInterface
{
...
}
public interface IYourInterface
{
string strMessage { get; }
bool cantAccessThisFn(string str);
}
Then your method should look like:
public IYourInterface objQ(string str)
{ ... }
And your assignment like this:
IYourInterface a = obj.objQ("A");
Now it is valid to call:
a.cantAccessThisFn("z");
This is to help you understand! and not the recommended solution.
Marked Patricks answer up, as that is the more correct way...
but to achieve what you had you could do something like.
Also I applied the standard naming camel cases for the Classes, Properties and local variables.
This also allows for ClsA and ClsB to have completely different Method/Property names. Again I am not suggesting this as the way to do it but to rather help understand what its happening.
public class Program
{
static void Main()
{
QMain obj = new QMain();
object a = obj.objQ("A");
//FYI the below commended out is not possible...
//ClsA.staticField is but that is not the instance you created.
//------------
//a.staticField //<--- not possible
//------------
var someA = a as ClsA; //<--- attempts to cast it as ClsA
var someB = a as ClsB; //<--- attempts to cast it as ClsB
if (someA != null) //check if the cast was successful
{
var var1 = someA.StrMessage;
}
else if (someB != null)
{
//...
}
}
}
public class QMain
{
public object objQ(string str)
{
if (str.ToUpper() == "A")
{
ClsA objA = new ClsA();
return objA;
}
else if (str.ToUpper() == "B")
{
ClsB objB = new ClsB();
return objB;
}
else
return "";
}
}
public class ClsA
{
public string StrMessage { get; private set; }
public static string StaticField;
public bool CantAccessThisFn(string str)
{
return true;
}
}
public class ClsB
{
public string StrMessageMyC { get; private set; }
public static string StaticFieldMyC;
public bool CantAccessThisFnMyC(string str)
{
return true;
}
}

Unable to perform cast

I need to have a wrapper class that exposes some properties of my entity class called ProfileEntity.
I tried doing it by deriving from this entity and then creating properties that return specific entity properties, but it says I cannot cast from ProfileEntity to ProfileEntityWrapper.
When I try to put the return values of a method that returns a 'ProfileEntity' into the wrapper I get the above error.
How do I create such a wrapper class that is castable?
Example
class ProfileEntityWrapper : ProfileEntity
{
public string Name
{
get
{
return this.ProfileEntityName;
}
}
}
public class Someclass
{
public ProfileEntity SomeMethod()
{
return ProfileEntity; // example of method returning this object
}
}
public class SomeOtherlClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
ProfileEntityWrapper ew = (ProfileEntityWrapper)sc.SomeMethod(); // Cannot do this cast!!!
}
}
You cannot cast an object of ProfileEntity to ProfileEntityWrapper.
var entity = new ProfileEntity(); // this object is only of type ProfileEntity
var wrapper = new ProfileEntityWrapper(); // this object can be used as both ProfileEntityWrapper and ProfileEntity
You probably want to return a ProfileEntityWrapper in SomeMethod():
public class Someclass
{
public ProfileEntity SomeMethod()
{
return new ProfileEntityWrapper(); // it's legal to return a ProfileEntity
}
}
No, that is not possible.
To accomplish this problem you can maybe try this one:
public class ProfileEntity
{
public string ProfileEntityName { get; set; }
}
public class ProfileEntityWrapper
{
public ProfileEntityWrapper(ProfileEntity entity)
{
Entity = entity;
}
public ProfileEntity Entity { get; private set; }
public string Name
{
get
{
return Entity.ProfileEntityName;
}
}
}
public class SomeClass
{
public ProfileEntity SomeMethod()
{
// example of method returning this object
ProfileEntity temp = new ProfileEntity();
return temp;
}
}
public class SomeOtherClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
//Create a new Wrapper for an existing Entity
ProfileEntityWrapper ew = new ProfileEntityWrapper(sc.SomeMethod());
}
}
If you are allowed to edit the ProfileEntity class, or if the ProfileEntity class is a generated partial class, you could add an interface instead of using a wrapper. You wouldn't need to do any casting with an interface either. Example:
public interface IProfile
{
string Name { get; }
}
public partial class ProfileEntity : IProfile
{
public string Name
{
get
{
return this.ProfileEntityName;
}
}
}
public class SomeClass
{
public ProfileEntity SomeMethod()
{
return ProfileEntity;
}
}
public class SomeOtherClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
IProfile ew = sc.SomeMethod();
}
}
The IProfile instance will only provide access to the Name property.
This's no correct code from polymorphism aspect.
If we will take the famous polymorphism example when there're base Shape class and Circle, Polygon and Rectangle classes that extend the Shape class, your code will try to cast some shape into circle and as you understand this's invalid casting operation.
So to make this code work you must be sure that SomeClass.SomeMethod() will return instance of ProfileEntityWrapper or perform type check before the casting, like this:
ProfileEntity temp = sc.SomeMethod();
if(temp is ProfileEntityWrapper)
ProfileEntityWrapper ew = (ProfileEntityWrapper) temp;

Categories

Resources