Abstract base classes and appdomains
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. How开发者_运维技巧ever, 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.
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.
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 = "...";
(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.
精彩评论