我想提供一些在我的软件中创建动态可加载插件的方法.执行此操作的典型方法是使用LoadLibrary WinAPI函数加载DLL并调用GetProcAddress以获取指向该dll内的函数的指针.
我的问题是如何在C#/ .Net应用程序中动态加载插件?
Managed Extensibility Framework是System.Addin的替代品吗?或者它们是互补的吗?
我正在开发一个大型应用程序,它包含许多较小的插件/应用程序.
它们不够大,不足以成为一个完整的进程,但是在一个进程中,它太小而无法在一个线程中运行,而我希望它基于一个插件基础.如果该插件的较新版本可用,则应该卸载,更新并重新启动.
在我寻找解决方案期间,我可以使用魔术字AppDomain,我引用:
"使用应用程序域来隔离可能导致进程失效的任务.如果正在执行任务的AppDomain状态变得不稳定,则可以卸载AppDomain而不会影响进程.当进程必须长时间运行而不重新启动时,这很重要您还可以使用应用程序域来隔离不应共享数据的任务."
因此,这正是我想要的.但是,我猜他们的"状态变得不稳定"与我的观点不同.我正在考虑一个问题,其中一个插件抛出异常,无论出于何种原因.我想抓住,通过电子邮件发送,卸载并重启(如果可能的话).
所以我创建了一个启动的应用程序,查找其文件夹中的所有.dll文件.检查dll是否包含插件.为该插件创建一个新的AppDomain,一旦加载了所有内容,它将启动每个插件.(每个插件可以由多个线程组成,与其他插件紧密共存).
所以我还在那里添加了一个超时,在5秒之后触发抛出一个新的Exception(); 在AppDomain上添加了UnhandledException事件来处理它.但是,它抓住了它,并且在导航之后,仍然"崩溃"了整个过程,包括所有额外的孩子 - AppDomains.
但它在报价中明确指出"隔离"可能"打倒流程"的任务.我错过了一些重要的东西吗?我对报价的看法是错误的吗?
我正在尝试实现类似应用程序的插件.我知道已经有几个解决方案,但这只是证明这个概念,仅此而已.这个想法是默认情况下使应用程序主应用程序几乎没有功能,然后让插件相互了解,让它们实现所有需要的功能.
出现了几个问题:
有没有专门处理这些.NET设计的书?
谢谢
编辑:我认为人们正在偏离我提出的两个问题.我可以看看MEF和#develop,但我想得到具体的问题答案.
我有一个程序,我开发使用基本的插件架构.实际上,当程序加载时,它使用反射在目录中搜索适合某个接口的dll,然后加载它们.现在看来,当前的插件列表将被使用.
因此,我目前检查dll文件的做法仍然是最佳做法,还是有更好的方法来加载每个dll?
谢谢.
我们有一个应用程序,作为其要求之一,它将采用任意第三方插件,加载它们,并在我们自己开发的应用程序旁边运行它们的UI.我们一直在将这些第三方插件加载到他们自己的AppDomain中以实现隔离,一切正常.
直到其中一个插件因未处理的异常而崩溃.在这种情况下,整个应用程序都会关闭,即使所有真正受到影响的应用程序都是我们的"额外"工具窗口之一.
理想情况下,我们想要一些方法来处理"未处理"的异常,卸载损坏的AppDomain,然后重新加载它. 问题是我们无法在事件处理程序中找到未处理异常的机制,我们可以将异常标记为"已处理".此外,由于插件具有自己的UI组件以及与用户自己的一组交互,因此在try/catch/finally块中"包装"我们与插件的交互是非常困难的.
是否有任何框架/编程库/模式可以解决这个问题?我们可以做插件很好; 我们需要帮助的是在不同AppDomain中的代码意外失败时保持应用程序活跃.
事件可以具有多个订阅者(即,在引发事件时可以调用多个处理程序).由于任何一个处理程序都可能抛出错误,并且这会阻止其余部分被调用,我想忽略从每个处理程序抛出的任何错误.换句话说,我不希望一个处理程序中的错误破坏调用列表中其他处理程序的执行,因为这些其他处理程序和事件发布者都无法控制任何特定事件处理程序代码的作用.
这可以通过以下代码轻松完成:
public event EventHandler MyEvent;
public void RaiseEventSafely( object sender, EventArgs e )
{
foreach(EventHandlerType handler in MyEvent.GetInvocationList())
try {handler( sender, e );}catch{}
}
Run Code Online (Sandbox Code Playgroud)
当然,我不想在每次调用事件时反复编写所有这些通用代码,所以我想将它封装在泛型类中.此外,我实际上需要额外的代码来确保线程安全,以便在执行方法列表时MyEvent的调用列表不会更改.
我决定将其作为泛型类实现,其中泛型类型受"where"子句约束为Delegate.我真的希望约束是"委托"或"事件",但那些是无效的,所以使用Delegate作为基类约束是我能做的最好的.然后我创建一个锁对象并将其锁定在公共事件的添加和删除方法中,这些方法会更改名为"event_handlers"的私有委托变量.
public class SafeEventHandler<EventType> where EventType:Delegate
{
private object collection_lock = new object();
private EventType event_handlers;
public SafeEventHandler(){}
public event EventType Handlers
{
add {lock(collection_lock){event_handlers += value;}}
remove {lock(collection_lock){event_handlers -= value;}}
}
public void RaiseEventSafely( EventType event_delegate, object[] args )
{
lock (collection_lock)
foreach (Delegate handler in event_delegate.GetInvocationList())
try {handler.DynamicInvoke( args );}catch{} …
Run Code Online (Sandbox Code Playgroud) 我正在用C#编写一个Addin框架,我想知道如何在不需要重新启动应用程序的情况下使Addin无法加载.
我听说过AppDomains但这些有用吗?Addin可以添加可扩展性类,并且可以通过接口在主AppDomain中调用,并且仍然可以卸载并调用清理代码,导致这些类被删除而该程序集不在主AppDomain中吗?
或者是否有其他方法可以实现无法加载的插件,但是除了AppDomain之外的IIRC,你无法卸载组件.
如果可能的话,我还希望插件引擎与Mono兼容,所以如果可以的话,任何答案都会尝试与Mono保持兼容.
我正在构建一个插件类型的系统,每个插件都表示为DLL.我希望能够在不停止主应用程序的情况下重新加载它们.这意味着它们必须在运行时加载,而不需要在它们之间预先建立链接(对dll执行文件搜索并加载它们).我使用此设置Assembly.LoadFile(filename)
,但是,当我尝试使用File.Copy
替换DLL时,它会引发异常,说类似于"正在使用的文件".我尝试过使用AppDomain
,通过这个辅助域加载所有插件,并在重新加载之前卸载它,但这会引发相同的异常.
我目前的代码:
if (pluginAppDomain != null)
AppDomain.Unload(pluginAppDomain);
foreach (string s in Directory.GetFiles(path_to_new_DLLs))
{
string name = s.Substring(s.LastIndexOf('\\') + 1);
Console.WriteLine("Copying " + name);
File.Copy(s, Path.Combine(current_directory, name), true); // Throws exception here
}
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Environment.CurrentDirectory;
setup.ShadowCopyFiles = "true";
// I think this is where the problem is, maybe I'm forgetting to set something
pluginAppDomain = AppDomain.CreateDomain("KhybotPlugin", null, setup);
foreach (String s in Directory.GetFiles(Environment.CurrentDirectory, "*.dll"))
{
int pos = s.LastIndexOf('\\') …
Run Code Online (Sandbox Code Playgroud) 有没有办法缓存每个应用程序启动(WPF)的MEF组件图,就像MAF一样,以避免在每次应用程序启动时发现目录并构建组件图.为了加快我的应用程序启动速度.MAF使用AddinsStore存储所有插件,当新插件发现存储重建并再次保存时.使用MEF设计的模块化应用程序可以做到这一点吗?
编辑:
在我的项目架构中我有扩展,模块和托管服务所以我有不同的导出像(IExtension,IModule,IManagedService),我处理所有组件的开始依赖项,我想要的正是ex(扩展目录)包含许多dll并且可能并非所有dll都包含(exports/Imports),因为某些dll只引用了一些Extensions.所以MEF的默认发现行为是在Extension Directory中的所有程序集中搜索exports/Imports,但我想通过查看所有dll并捕获类型及其名称和dll以在其中使用它们来修改此行为下一个启动时间.从catch直接加载组件(Exports),以便MEF知道可用的组件及其位置,而无需加载和搜索dll.它看起来像是一个Exports及其Places和依赖项的字典,可以直接从它的地方(dll)获取实例.