Question

I'm am currently revising a plugin architecture so that it utilizes AppDomains. The main difference between my plugins and the many examples I have found online is that instead of the plugin running and sending its results back to the main application, my main application is the one sending information to the plugin.

As it currently stands, I create an instance of the loader in a separate AppDomain. It then does all your normal initialization such as loading the plugin assembly. As this point, I then use the proxy of the loader to call the methods that send the data from the main application to the new AppDomain.

My problem occurs when I am attempting to call a method which has an argument type that is not serializable, and which does not derive from MarshalByRefObject.

Since these types are from 3rd party code, and the plugins expect to receive them, I cannot seem to find a way do this. After finding this question ( How to solve "Must be MarshalByRefObject" in a good but multiple-inheritance amputated language like C#? ), I was thinking about creating some sort of wrapper. My drawback here is that I simply cant figure out a way to make one without modifying the 3rd party code.

Here is an example of my issue:

// Cant modify this class
class ThirdPartyClass
{
    // The properties are also 3rd party and nonserializable. These are accessed by the plugins.
    public AnotherClass Property1{ get; set; }
    public AnotherClass Property2{ get; set; }

    public ThirdPartyClass(){}
}

class Loader : MarshalByRefObject
{
    private Plugin plugin;

    public Loader()
    {
        Assembly pluginAssembly = Assembly.LoadFrom("Full/Assembly/Path");
        plugin = pluginAssembly.CreateInstance("Full.Plugin.Name") as Plugin;
    }

    public void DoSomething(ThirdPartyClass o)
    {
        ...
        plugin.DoSomethingElse(o);
    }
}

class PluginManager
{
    void Main(ThirdPartyClass o)
    {
        AppDomain pluginAppDomain = AppDomain.CreateDomain("Plugin AppDomain");
        Loader loader = pluginAppDomain.CreateInstanceFromAndUnwrap("Full/Loader/Path", "Full.Loader.Name") as Loader;

        // This is where I would have a problem.
        loader.DoSomething(o);
    }
}

Any help would be greatly appreciated.

Was it helpful?

Solution

Do you need to have the appdomain interact with the 3rd party object and it reflect back on the other side? If not (and based on your title it sounds like you wouldn't mind them being serializable) then why not serialize them? By that I mean so something similar to:

[Serializable]
class MyThirdPartyClass : ThirdPartyClass, ISerializable
{
    public MyThirdPartyClass()
    {
    }

    protected MyThirdPartyClass(SerializationInfo info, StreamingContext context)
    {
        Property1 = (AnotherClass)info.GetValue("Property1", typeof(AnotherClass));
        Property2 = (AnotherClass)info.GetValue("Property2", typeof(AnotherClass));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Property1", Property1);
        info.AddValue("Property2", Property2);
    }
}

Of course there are caveats with this approach, firstly it relies on you being able to derive the class and secondly it requires you to manually serialize the data (to a degree). You could automate that using reflection on the internal fields which is realistically the only thing you need to worry about and reconstruct on the other side, effectively manually serializing.

You might have been able to implement a surrogate selector but it seems it isn't exposed to the developer to change the default inter appdomain one :(

OTHER TIPS

If these are just instances that are crossing the app domain boundaries, meaning you dont use them in more than that one app domain, you can simply wrap them in a holder class that derives from MarshalByRefObject.

I use a similar approach in IronScheme's remoting code.

The problem is when you actually need to do more than just hold on to the instance. In this case, you can probably use interfaces to hook the needed methods and expose that via the 'holder' class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top