views:

255

answers:

2

I'm writing a program which will allow to load a specific managed .DLL file and play with it. Since I want the ability to unload the .DLL file, I'm creating two AppDomains - one for the app itself, the other for the currently loaded .DLL.

Since most of the objects in the loaded .DLL do not serialize well, I'm creating a MarshalByRefObject wrapper class which will keep the object itself in its own AppDomain, and expose some reflection functions to the main application AppDomain.

However when I try to invoke a method on the remote object I get stuck with an exception:

Permission denied: cannot call non-public or static methods remotely.

This is very strange, because I'm not using any non-public or static methods at all. In essence, what I have is:

class RemoteObjectWrapper: MarshalByRefObject
{
    private Type SourceType;
    private object Source;

    public RemoteObjectWrapper(object source)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        this.Source = source;
        this.SourceType = source.GetType();
    }
    public T WrapValue<T>(object value)
    {
        if ( value == null )
            return default(T);
        var TType = typeof(T);
        if (TType == typeof(RemoteObjectWrapper))
            value = new RemoteObjectWrapper(value);
        return (T)value;
    }
    public T InvokeMethod<T>(string methodName, params object[] args)
    {
        return WrapValue<T>(SourceType.InvokeMember(methodName,
            System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Instance |
            System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public, null, this.Source, args));

    }
}

And I get the exception when I try to do:

var c = SomeInstanceOfRemoteObjectWrapper.InvokeMethod<RemoteObjectWrapper>("somePublicMethod", "some string parameter");

What's going on here? As far as I can understand, the InvokeMethod method doesn't even get executed, the exception is thrown when I try to run it.

Added: To clarify - SomeInstanceOfRemoteObjectWrapper is constructed in the .DLL's AppDomain and then returned to my main AppDomain, The InvokeMethod<T>() is called from my main AppDomain (and I expect it to execute in the .DLL's AppDomain).

+2  A: 

Even the method InvokeMethod<T> is public it is contained within an internal class. No modifier in C# makes it internal. Hence the effective visibility of InvokeMethod<T> is internal and you are getting the exception. Making RemoteObjectWrapper public should fix this problem.

JaredPar
Weird... this works... but then why none of the other similar classes need it? This is the only remote object wrapper class that needs it (I have a few others that wrap specific objects and those are not affected)
Vilx-
A: 

I have the exact same problem. If you an object such as:

class MyClass : MarshalByRefObject
{
  public T Foo<T>() where T : MarshalByRefObject {
    // stuff
  }
}

Calls to MyClass.Foo with an internal type T work fine but only as long as your MyClass object is not remote. I suppose this is because you can't necessarily assume the place you're making the call to has any access to T. It's very awkward, however, when you can't make the type you're using public. You can sometimes get around it by wrapping or replacing Foo with:

class MyClass : MarshalByRefObject
{
  public object Foo(Type t) {
    // stuff
  }
}

Which isn't type safe at all and requires a cast on the caller's side. I don't know if there's a better solution, though, if you can't be bothered to expose your internal type.

Aeka