使用抽象类作为插件框架中的契约

发布于 2024-08-22 19:09:00 字数 1557 浏览 4 评论 0原文

抽象类可以用作“主机”和“插件”之间的契约对象吗?这个想法是插件继承契约(我们称之为适配器)。我们还了解到,框架中的所有参与者都必须继承 MarshalByRefObject (MBRO)。所以,这就是我们的想法 -

主机

class Host : MarshalByRefObject
{
}

合同

public abstract class PluginAdapter : MarshalByRefObject
{
}

插件

class myPlugin : PluginAdapter
{
}

这三个都存在于单独的汇编语言中。我们的主机将为每个插件创建一个新的AppDomain,并且PluginAdapter的创建如下:

{
    ObjectHandle instHandle = Activator.CreateInstance(
    newDomain, data.Assembly.FullName, data.EntryPoint.FullName);

    PluginAdapter adapter = (PluginAdapter)instHandle.Unwrap();
}

编辑:其中datamyPlugin的具体类型。

我们想知道该框架的实施是否可行。我们已经看到一些文章使用接口(IPlugin)进行插件派生,并使用具体类作为契约。这些文章还说可以使用抽象类,但没有给出该实现的示例。是否要求合约是具体类?

编辑: 在此示例中,作者为 Richard Blewett - C# Reflection - 他使用了一个更简单的实现:

Contract:

public interface IPlugIn  
{  
    // do stuff  
}

Plugin:

public class PlugIn : MarshalByRefObject, IPlugIn  
{  
}

现在,如果使用抽象类作为合约,插件不能同时继承合同和MBRO。那么,什么就成为可扩展插件框架的最佳实现。即使我们最初是针对单机操作进行开发,我们是否应该继续实施远程处理?该项目预计将分布在网络上,也可能分布在互联网上。我们只是还没有实现 Tcp,因为我们正在尝试完全理解和操作插件​​框架的基础知识。

使用环回在单台机器上实现 Tcp 远程处理是否有意义?

Can an abstract class be used as the contract object between a 'Host' and a 'plugin'? The idea is that the plugin inherits the contract (we call it an adapter). We are also understanding that all participants in the framework must inherit MarshalByRefObject (MBRO). So, this is what we were thinking -

Host:

class Host : MarshalByRefObject
{
}

Contract:

public abstract class PluginAdapter : MarshalByRefObject
{
}

Plugin:

class myPlugin : PluginAdapter
{
}

All three exist in separate asm's. Our Host will create a new AppDomain for each plugin, and the PluginAdapter is created as follows:

{
    ObjectHandle instHandle = Activator.CreateInstance(
    newDomain, data.Assembly.FullName, data.EntryPoint.FullName);

    PluginAdapter adapter = (PluginAdapter)instHandle.Unwrap();
}

EDIT: where data is the concrete type of myPlugin.

We were wondering if this implementation of the framework would work. We have seen articles using an interface (IPlugin) for the plugin derivation, and a concrete class as the contract. Those articles would also say that an abstract class can be used, but no examples of that implementation given. Is it required that the contract be a concrete class?

EDIT:
In this example by Richard Blewett - C# Reflection - he uses a much simpler implementation:

Contract:

public interface IPlugIn  
{  
    // do stuff  
}

Plugin:

public class PlugIn : MarshalByRefObject, IPlugIn  
{  
}

Now, if using an abstract class as the contract, the Plugin cannot inherit both the contract and MBRO. What, then, becomes the best implementation for a scalable plugin framework. Should we go ahead and implement remoting even though, initially, we are developing for single-machine operation? This project is expected to become distributed across a network, possibly across the Internet as well. We simply have not implemented Tcp yet because we are trying to get the basics of a plugin framework fully understood and operational.

Does it make sense to implement Tcp remoting on a single machine using loopback?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

纸短情长 2024-08-29 19:09:00

恕我直言,抽象类是更好的选择。这主要是因为接口更难版本化。 此博文介绍了您可能会发现的问题如果你不使用基类,就已经走下去了。顺便说一句,这条规则不仅适用于插件。

关于你的设计...

插件不应该扩展MBRO。您应该使用您的主机(应扩展 MBRO)来编组对插件的所有调用,包括处理插件事件。如果您尝试将插件 DLL 拉过来并使用它们的代理,则很容易无意中将插件 DLL 加载到您的主应用程序域中。

例如,如果插件为其方法之一返回 IEnumerable,则它可能返回插件程序集中定义的 IEnumerable 实现。如果这不扩展 MBRO,主应用程序域将必须加载插件程序集。


我在这里上传了三个处理应用程序域的项目:

http://cid-f8be9de57b85cc35.skydrive.live.com/self.aspx/Public/NET%20AppDomain%20Tests/appdomaintests.zip

一是跨appdomain使用回调,二是跨appdomain事件处理,第三个是插件示例。

在插件示例中,应用程序定义了一个插件接口(它是一个演示,而不是最佳实践!)和一个插件主机。该应用程序从磁盘加载原始插件程序集,并通过插件主机代理将其传递到插件应用程序域,并在其中加载。然后插件主机实例化插件并使用它。但是,当主机将插件程序集中定义的类型返回到应用程序 appdomain 时,插件程序集将加载到主应用程序域中,从而使整个插件变得毫无意义。

避免这种情况的最佳方法是为未标记为可序列化且不扩展 MBRO 的插件提供一个抽象基类,并且仅带回您从插件域边界跨界定义的原语或密封类型。

注意:这些项目都是 4.0 RC。您将需要这个或以上来运行它们。否则,您将必须手动编辑项目文件或重建它们才能在 b2 或 2008 中运行。

Abstract classes are better choices for this, imho. Its primarily because interfaces are harder to version. This blog post describes the issue you might find yourself having down the road if you don't use base classes. This rule doesn't only apply to plugins, btw.

About your design...

Plugins shouldn't extend MBRO. You should use your Host (which should extend MBRO) to marshall all calls across to your plugins, including handling plugin events. Its very easy to unintentionally load a plugin DLL into your main appdomain if you attempt to pull them across and use their proxies.

For example, if the plugin returns an IEnumerable for one of its methods, it may return an implementation of IEnumerable that is defined in the plugin assembly. If that doesn't extend MBRO the main appdomain will have to load the plugin assembly.


I've uploaded three projects dealing with appdomains here:

http://cid-f8be9de57b85cc35.skydrive.live.com/self.aspx/Public/NET%20AppDomain%20Tests/appdomaintests.zip

One is using callbacks across appdomains, the second is cross-appdomain event handling, and the third is a plugin example.

In the plugin example, an application defines a plugin interface (its a demo, not best practices!) and a plugin host. The app loads a plugin assembly raw from disk and passes it over to the plugin appdomain via the plugin host proxy, where it is loaded. The plugin host then instantiates the plugin and uses it. But when the host returns a type defined in the plugin assembly back over into the application appdomain, the plugin assembly is loaded into the main application domain, rendering the whole plugin thing pointless.

Best thing to avoid this is provide an abstract base class for plugins that is not marked serializable and does not extend MBRO, and to only bring back primitives or sealed types you define back across the boundary from the plugin domain.

NOTE: the projects are all 4.0 RC. You'll need this or above to run them. Otherwise you'll have to edit the project files by hand or rebuild them to get them running in b2 or 2008.

春庭雪 2024-08-29 19:09:00

假设“data.EntryPoint.FullName”是完整的类型名称,上面的代码应该可以工作。

但是,如果您尝试将此类型隔离在其自己的 AppDomain 中,那么您应该小心。通过执行data.Assembly,您会将程序集(及其类型)拉入您的AppDomain,从而导致类型加载到正在执行的AppDomain中...

Provided "data.EntryPoint.FullName" is the full type name, the above code should work.

However, if you're trying to keep this type isolated in its own AppDomain, you should be careful here. By doing data.Assembly, you'll pull the assembly (and it's types) into your AppDomain, causing the types to be loaded in the executing AppDomain...

甜是你 2024-08-29 19:09:00

您可能需要查看MAF(托管插件框架) 这是一个内置于 .NET 中的可扩展框架,用于执行插件。它与 MEF(托管可扩展性框架) 类似(且更旧),但在保持除其他外,他们自己的应用程序域中的插件。

You may want to take a look at MAF (the Managed Addin Framework) which is an extensibility framework built into .NET for doing Addins. It is similar (and older) than MEF (Managed Extensibility Framework), but has more options as far as keeping plugins in their own app domain, among other things.

橘虞初梦 2024-08-29 19:09:00

如果 data.EntryPoint.FullName 引用具体类型 myPlugin 我看不出有任何原因这不起作用(除非在其他应用程序域中存在程序集加载问题)但这是另一个问题)。

If data.EntryPoint.FullName refers to the concrete type myPlugin I don't see any reason why this wouldn't work (unless than having assembly loading issues in the other appdomain but that's a different issue).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文