views:

179

answers:

3

I apologize now if my upcoming explanation doesn't make enough sense; I'm reknown for it, though I try to do otherwise.

I'm writing a service that makes use of user-defined plugins. I'm trying to isolate them -- keeping their assemblies out of the service's appdomain -- by making use of interfaces defined in a shared assembly.

What's killing me is the use of abstract base classes. There is functionality that will be common to all implementations of some of the interfaces, so abstract base classes make sense. If an abstract base is in the service assembly, then whatever plugins that subclass it get their assemblies dragged into the service's appdomain. However, there are internal members in the abstract base (properties with internal setters and public getters) that the service uses so it needs to be in the same assembly as the service for that to be possible.

It seems like what I want is not possible, but I also believe that it's because I'm taking the wrong approach. I'm desperately trying to make better use of good patterns and practices in this exercise and learning along the way.

A: 

What you probably want is an interface with an abstract base class that implements the interface and derived classes can inherit from. In this case you can maintain your separation with the interface but still provide the abstract base class for implementation. This also has the advantage that the abstract base class is optional.

A: 

If the problem you are trying to avoid is leaking the plug-in assembly into your service AppDomain, then you won't have that problem whether you have internal members or not. You will simply need the service assembly to be available inside the plugin domain (not the other way around) and you'll probably have to define the shared type in the service assembly rather than a separate assembly (if you indeed need "internals" of the other assembly).

Imagine you have abstract base class PluginBase defined in ServiceLib.dll. You could then have code like this in your main service AppDomain:

// Create a new AppDomain for the plugin
AppDomain pluginDomain = AppDomain.CreateDomain("PluginDomain", null, new AppDomainSetup());

// Instantiate the plugin type (in the new AppDomain)
// Note: assumes that PluginBase is MarshalByRefObject
PluginBase plugin = (PluginBase)domain.CreateInstanceAndUnwrap("PluginLib", "PluginLib.PluginImp");

// Set any internal stuff now
plugin.InternalDetails = "...";
bobbymcr
And this is actually what I'm doing currently. However, when I set the internal property defined in the base class, that's when it brings the plugin's assembly into the service's appdomain. I'm guessing that it's because it's an abstract base and type information is needed from the plugin assembly (and it really is a GUESS).
oakskc
Hmm, I just tried this and it looks like I'm seeing the same behavior as you... as soon as you load the class into the other AppDomain it loads the plug-in assembly into the main AppDomain. When you use an interface, this doesn't occur, but of course that doesn't help you with defining the common implementation. What seems to work is defining an interface and a base class which implements the interface; then when you load the type, you cast only to the interface and it won't load the other assembly. This still may not quite do what you want because interfaces don't allow mixed visibility.
bobbymcr
A: 

(For my and possibly others' future reference)

It turns out that this was a somewhat pointless exercise.

Once the plugin-created object's proxy was available in other appdomains, anything in that service-defined base class that makes use of the service in an internal fashion (like a lookup against a collection), it operates against the copy of the service object in the plugin's appdomain, not the singleton I'm trying to provide.

I think I'm down to either abandoning my multiple-appdomain quest or abandoning doing anything internally. If there are no internal operations, the base class can be split from the service, but then it has to interact with the service just like everything else does.

I do enjoy learning, but I do not appreciate the bumps on the head along the way.

oakskc