内置的Ninject装配装载程序是否存在错误处理

时间:2014-06-04 14:35:41

标签: c# plugins dependency-injection ninject

我已经写了一个插件管理器

public class WeinCadPluginManager : NinjectModule, IEnableSerilog
{
    public override void Load()
    {

        var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
        var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
        var dirPath = Path.GetDirectoryName(codeBasePath);
        Debug.Assert(dirPath != null, "dirPath != null");
        var path = dirPath;

        var types = Directory
            .GetFiles(path, "*.dll")
            .Select (Assembly.LoadFile)
            .SelectMany (assembly =>
                {
                    try
                    {
                        return assembly.GetExportedTypes();
                    }
                    catch (Exception e)
                    {
                        this.Serilog()
                            .Error
                            (e, "Failed to load assembly {assembly}", assembly);
                        return new Type[]
                        {
                        };
                    }
                })
            .Where(type=>typeof(IWeinCadPlugin).IsAssignableFrom(type))
            .ToList();

        foreach (var assembly in types)
        {
            Kernel.Bind<IWeinCadPlugin>().To(assembly).InSingletonScope();
        }
    }
}

现在这几乎是重复的

Kernel.Load("*.dll")

除非从程序集中导出类型时出现任何错误,否则Kernel.Load崩溃且无法进行错误处理。我不希望失败加载单个插件程序集来崩溃我的应用程序。我的解决方案是唯一可行的方法,还是Ninject有一些错误处理可用?

1 个答案:

答案 0 :(得分:1)

我认为每个try { } catch { }周围的Kernel.Load("specificplugin.dll")就足够了。 您仍然需要自己查找所有程序集,但必须编写更少的代码。

var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);

var dllPaths = Directory.GetFiles(dirpath, "*.dll");

foreach(string dllPath in dllPaths)
{
     try
     {
         kernel.Load(dllPath);
     }
     catch (Exception e)
     {
         this.Serilog()
             .Error(e, "Failed to load assembly {assembly}", assembly);
     }
}

缺点:ninject必须在.Bind().To(..)上添加绑定到内核,因为所有其他的流畅语法方法都是可选的。因此,如果.When().InScope(),..任何其他可选方法中存在异常,您将留下非完整绑定,因此很可能是一个有缺陷的软件。

(但我怀疑大多数错误在创建绑定时都不会实现,而是在激活绑定时实现。而且你没有受到保护。)

据我所知,一旦你添加了绑定,就无法从ninject中删除绑定。除了.Rebind() - 但总是用不同的绑定替换绑定。 所以不,我不会想到像#&#34;回滚异常&#34;。

所以我们必须寻找替代解决方案。有一个:子内核。 https://github.com/ninject/ninject.extensions.childkernel

将每个插件加载到自己的子内核中。如果fooplugin.dll加载失败,请处置子内核。如果它有效..你很高兴去! :) 这也具有插件不能相互影响的优点。想象一下,两个插件可以IBindingRoot.Bind<string>().ToConstant("some constant"); - )

(请注意,我还没有测试在父内核工作之前是否处理子内核&#34;正如预期的那样#34;所以你应该先测试它。很简单,对吗?)