【问题标题】:How to use Hangfire when using MEF to load plugins?使用MEF加载插件时如何使用Hangfire?
【发布时间】:2017-12-15 08:47:30
【问题描述】:

我在我的 WebApi 项目中使用 MEF 来加载位于 bin 文件夹以外的文件夹中的插件。我执行以下操作:

var directoryCatalog = new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins"));

var container = new CompositionContainer(directoryCatalog);
container.ComposeParts();

IList<IPlugin> plugins = container.GetExportedValues<IPlugin>().ToList();

然后我正在设置一个插件:

plugins[0].Startup(logService, unitOfWork);

注意:我没有使用[ImportingConstructor] 传递上述依赖项,因为我使用的是已经在控制器中实例化的现有实例。

然后我将作业安排如下:

BackgroundJob.Schedule(() => plugins[0].Start(), new TimeSpan(0, 0, 1));

但是,当 Hangfire 尝试启动作业时,我收到以下异常:

无法加载文件或程序集“App.Plugins.FirstPlugin,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”或其依赖项之一。系统找不到指定的文件。

在这种情况下甚至可以同时使用 MEF 和 Hangfire 吗?如果是,正确的程序是什么?

注意: 如果插件 DLL 与主应用程序位于同一 bin 文件夹中,则 Hangfire 可以正常工作。但这违背了拥有单独插件文件夹的目的。

【问题讨论】:

    标签: c# asp.net-web-api mef hangfire


    【解决方案1】:

    您需要通过订阅AppDomain.AssemblyResolve 事件(在启动hangfire 服务器之前的某个位置)来引导hangfire(或者更确切地说- .NET 本身)找到此程序集的位置:

    var pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
        var asmName = new AssemblyName(args.Name);
        var plugin = Path.Combine(pluginPath, asmName.Name + ".dll");
        if (File.Exists(plugin))
            return Assembly.LoadFrom(plugin);
        return null;
    };
    

    由于您的插件实际上已经加载到当前应用程序域中(通过 MEF),以下也应该可以工作(我认为可能比上面更好):

    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
        var asmName = new AssemblyName(args.Name);
        var existing = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(c => c.FullName == asmName.FullName);
        if (existing != null) {
            return existing;
        }
        return null;
    };
    

    这是必要的,因为 hangfire,要从数据库中的状态反序列化插件实例,使用 Type.GetType 提供程序集限定名称,并且由于某些复杂性(我认为)与这个问题无关 - Type.GetType 不会找到你的插件程序集,即使它已经被 MEF 加载到当前的应用程序域中,所以你必须帮助它。

    【讨论】:

    • 我把上面的代码放在Application_Start里面Global.asax里面。还是有同样的问题。
    • @Ivan-MarkDebono 尝试第一个代码块(使用pluginPath 的代码块)并将其作为第一个语句放入Application_Start
    • @Ivan-MarkDebono 我还修复了第二个代码块(不使用 pluginPath),它现在应该也可以在 Application_Start 中使用。
    【解决方案2】:

    Hangfire Extensions 页面上,有一个关于 NuGet 包 Hangfire.MEF 的概念。

    它指向Hangfire.MEF - Hangfire background job activator based on MEF IoC Container。我认为它可能会帮助您解决问题。

    【讨论】:

    • 据我了解,这个扩展是用来通过MEF部分的构造函数注入依赖的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    相关资源
    最近更新 更多