4

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

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • 1
    It would be useful to see the stack trace and the calling code and the remote object code, but it sounds like somePublicMethod may be static. – pdr Mar 23 '10 at 04:28
  • 1
    @pdr - No, execution never passes into `InvokeMethod`. The exception is thrown EXACTLY at the line above, and the stack trace proves it too. I won't post it here because it contains no other useful information, but the line of code where the exception is thrown is this one, and there is no inner exception or anything. – Vilx- Mar 23 '10 at 11:44

2 Answers2

5

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
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    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- Mar 23 '10 at 11:41
3

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
  • 51
  • 1