我已经写了一个插件管理器
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有一些错误处理可用?
答案 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;所以你应该先测试它。很简单,对吗?)