.Net插件框架选择,允许定义插件顺序(包括链式插件)

发布于 2024-09-18 08:41:31 字数 894 浏览 3 评论 0原文

[我已经阅读了之前关于 MEF、MAF、DI 等的文章,它们并没有帮助我解决我的具体问题]

我希望编写一个可扩展的 .Net 应用程序(可能是控制台或 Windoes 服务)。它是一个夜间/计划应用程序,用于从数据库中提取数据,对其执行某些操作,然后输出它(或将其传递到另一个系统)。

我不确定为插件定义此过程的最佳方法是什么。这些组件是:

  • 任务 - 实际任务的定义,包含插件定义以及运行时间的基于事件的标志(EOD、EOW、EOM)
  • - 的源数据(一个任务将有一对多来源),这可能是 SQL 查询/存储过程、Web 服务,或者可能是一个文件。我看到这输出了一个数据表。
  • PostProcess - 需要对源输出进行的处理(任务将没有或多个后期处理步骤),这可能是聚合器或某种特定的处理)。这将接收一个数据集(包含上一步中的数据表)。由于依赖性,这些必须按特定顺序运行。
  • 目标 - 最终结果(也是一对多),这可能是 SQL 语句/存储过程、专有数据加载、电子邮件、输出文件或 Web 服务

为了简化它,我更喜欢插件可以从配置文件中读取,这意味着我不需要知道要传递给插件的连接字符串(和其他详细信息)。

我研究过 MEF、MAF、DI,或者只是定义了我自己的框架。在这个阶段,我倾向于发展自己的,只是想知道我是否错过了什么?

我实际上想使用 MEF,但是因为我需要定义我的任务(即任务链接到哪个 Sources 链接到哪个 PostProcess 链接到哪个 Target),并且也无法访问配置。我已经看到 MEF Primatives 和 Type Catalogs 为我提供了一部分帮助,但似乎对我的插件链接没有帮助。 MEF 是一个有效的选择吗?

[I have read previous posts on MEF vs MAF vs DI etc, they aren't helping me with my specific problem]

I am looking to write a .Net application (probably console or Windoes service) which will be extensible. It is an overnight/schedule app to extract data from a database, do something with it, and then output it (or pass it on to another system).

I am unsure what the best way to define this process for plugins. The components are:

  • Task - definition of the actual task, containing plugin definitions, and event based flag on when to run (EOD,EOW,EOM)
  • Source - the source of the data (a task will have one to many sources), this could be a SQL query/stored proc, web service, or perhaps a file. I see this outputting a datatable.
  • PostProcess - the processing required to be done on the Source output (a task will have none to many post process steps), this could be an aggregator or some sort of specific processing). This would receive a dataset (containing the data table/s from the previous step). These would have to run in a specific order due to dependancies.
  • Target - the end result (also one to many), this could be a SQL statement/stored proc, a proprietary data load, email, output file or a web service

To simplify it I would prefer that the plugins could read from the config file, this would mean I wont need to know what connection strings (and other details) to pass to plugins.

I have looked at MEF, MAF, DI, or just defining my own framework. At this stage I am leaning towards developing my own, just wondered if I had missed anything?

I would actually like to use MEF, however as I need to define my task (ie. Task links to which Sources links to which PostProcess links to which Target), and also not having access to config. I have seen MEF Primatives and Type Catalogs get me part of the way, but doesn't seem to help my chaining of plugins. Is MEF a valid choice?

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

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

发布评论

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

评论(3

拥抱没勇气 2024-09-25 08:41:31

MEF绝对是一个有效的选择。然而,我不认为 MEF 被设计为一个成熟的插件系统,它只是一个很好的起点! MEF 处理所有脏组件的加载和处理,但任何特定的先决条件都需要手动检查。为此,我建议使用元数据。元数据允许您将信息与导入之前可以读取的导出关联起来 (MEF 元数据

[Export(typeof(ITask))]
[ExportMetadata("Requires", "source1")]
public class Task1: ITask
{
    ...
}

使用 MEF 传递配置很简单。主机应用程序可以导出其自身,所有插件都导入它并可以访问其接口。请参阅下面的示例:

接口:

public interface IMainApp
{
    ConfigClass Config { get; set; } 
}

主机应用程序:

[Export(typeof(IMainApp))]
public class Host : IMainApp
{
    public Host()
    { /* Compose parts here..? */ }

    public ConfigClass Config { get; set; }  

    [Import(typeof(IModule))]
    public List<IModule> LoadedModules { get; set; }
}

插件程序集:

[Export(typeof(IModule))]
public class Module : IModule
{        
    public Module() { }

    [Import(typeof(IMainApp))]
    public IMainApp Host { get; set; } 

    public void DoSomething()
    {
        Host.Config... // use config here
    }
}

MEF is definitely a valid choice. However, I dont think MEF was designed to be a fully fledged plug-in system, it is intended as a good starting point! MEF handles all the dirty assembly loading and disposing, but any specific pre-requisites need to checked manually. For this I would recommend using metadata. Metadata allows you to associate information with exports that can be read before you import them (MEF Metadata)

[Export(typeof(ITask))]
[ExportMetadata("Requires", "source1")]
public class Task1: ITask
{
    ...
}

Passing the config through with MEF is simple. The host application can export its self and all the plugins import it and have access to its interface. See my example below:

Interface:

public interface IMainApp
{
    ConfigClass Config { get; set; } 
}

Host App:

[Export(typeof(IMainApp))]
public class Host : IMainApp
{
    public Host()
    { /* Compose parts here..? */ }

    public ConfigClass Config { get; set; }  

    [Import(typeof(IModule))]
    public List<IModule> LoadedModules { get; set; }
}

Plug-in assembly:

[Export(typeof(IModule))]
public class Module : IModule
{        
    public Module() { }

    [Import(typeof(IMainApp))]
    public IMainApp Host { get; set; } 

    public void DoSomething()
    {
        Host.Config... // use config here
    }
}
如梦初醒的夏天 2024-09-25 08:41:31

听起来您想做我们所说的显式接线。 MEF 默认情况下不支持这一点,因此您必须克服一些困难才能做到这一点。我相信 MEF Contrib 上有一个配置驱动的编程模型,它可能会对您有所帮助。

It sounds like you want to do what we call explicit wireup. MEF doesn't support that by default so you would have to jump through some hoops to do so. I believe there is a config-driven programming model on MEF Contrib, which might help you.

┈┾☆殇 2024-09-25 08:41:31

您可能需要查看 Mono.Addins。您可以为每个部分定义一个扩展点(以便插件可以定义新类型的源或目标),然后您可以创建一个扩展点来定义任务。在后面的扩展点中,您将定义每个任务以及它们与源和目标的关系。

例如,可以在插件中定义如下所示的源:

[Extension (Id="MySource")]
class MySource: ISource
{
  ...
}

用于定义任务的扩展点可以如下所示:

<Extension path="/MyApp/Tasks">
    <Task id="someTask">
        <Source sourceId="MySource" />
        <Target targetId="MyTarget" />
    </Task>
    ...
</Extension>

You may want to take a look to Mono.Addins. You could define an extension point for each of the parts (so plugins can define new types of Sources or Targets), and then you could create an extension point for defining tasks. In the later extension point, you would define each tasks and how they relate to sources and targets.

For example, a source could be defined in a plugin like this:

[Extension (Id="MySource")]
class MySource: ISource
{
  ...
}

And the extension point for defining tasks could be like this:

<Extension path="/MyApp/Tasks">
    <Task id="someTask">
        <Source sourceId="MySource" />
        <Target targetId="MyTarget" />
    </Task>
    ...
</Extension>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文