如何实现.NET插件,而无需使用应用程序域?如何实现、应用程序、插件、NET

2023-09-02 01:55:16 作者:白狼的爱

问题陈述:实现一个插件系统,使相关的组件被覆盖(避免文件锁定)。在.NET中,具体的组件可能无法卸载,只有整个应用程序域可以被卸载。

我张贴这一点,因为当我试图解决这个问题,每个解决方案参考了使用多个应用程序域。多个AppDomain是很难实现正确的,即使在一个项目开始架构。

此外,应用程序域没有适合我,因为我需要跨域作为语音服务器worfklow的InvokeWorkflow活动设置传输类型的工作。不幸的是,跨域发送一个类型使组件被注入到本地应用程序域

此外,这是有关IIS。 IIS有卷影副本设置,允许同时其加载到内存中执行的程序集被覆盖。问题是,(至少在XP下,对生产没有测试2003的服务器),当您以编程方式加载程序集,卷影副本不工作(因为你正在加载的DLL,不是IIS)。

解决方案 检查是否已经装入装配(为了避免引起一遍又一遍的加载同一个组件内存泄漏)。 如果没有加载它,阅读组装成一个字节数组。这将prevent锁定该文件。 供应字节数组作为实际参数的到的Assembly.Load

下面code可以让你知道一个程序集的全名。

 组装装配= NULL;

的foreach(大会loadedAssembly在AppDomain.CurrentDomain.GetAssemblies())
    如果(loadedAssembly.FullName ==foobar的,版本= 1.0.0.0,文化=中性公钥=空)
    装配= loadedAssembly;

如果(组装== NULL)
{
    byte []的studybin = System.IO.File.ReadAllBytes(@C: pathToAssembly  foobar.dll);
    装配=的Assembly.Load(studybin);
}
 

请注意,如果你正在努力寻找一个特定的组件目录中,可以运行System.Reflection.AssemblyName.GetAssemblyName(路径);看是否匹配全名,你在找什么。 GetAssemblyName(路径)不大会不要注入到当前的AppDomain。

另外请注意,这个解决方案是不适合的应用程序必须很少重新启动与所述组件以高频变化。装配每次加载时,你应用程序的内存占用量将会增长。有没有方法来卸载的组件,从而缩小内存使用情况的唯一选择就是重新启动应用程序。然而,该限制常常preferable到大的性能,存储器,和code复杂使用多个应用程序域的开销。这种限制也是不可避免的,如果你想与键入秒。

工作

Problem statement: Implement a plug-in system that allows the associated assemblies to be overwritten (avoid file locking). In .Net, specific assemblies may not be unloaded, only entire AppDomains may be unloaded.

应用程序无法正常启动0xc0000142怎么办

I'm posting this because when I was trying to solve the problem, every solution made reference to using multiple AppDomains. Multiple AppDomains are very hard to implement correctly, even when architected at the start of a project.

Also, AppDomains didn't work for me because I needed to transfer Type across domains as a setting for Speech Server worfklow's InvokeWorkflow activity. Unfortunately, sending a type across domains causes the assembly to be injected into the local AppDomain.

Also, this is relevant to IIS. IIS has a Shadow Copy setting that allows an executing assembly to be overwritten while its loaded into memory. The problem is that (at least under XP, didnt test on production 2003 servers) when you programmatically load an assembly, the shadow copy doesnt work (because you are loading the DLL, not IIS).

解决方案

Check if the assembly is already loaded (to avoid memory leaks caused by loading the same assembly over and over again). If its not loaded, read the assembly into a byte array. This will prevent locking the file. Supply the byte array as an arguement to Assembly.Load

The following code assumes you know the FullName of an assembly.

Assembly assembly = null;

foreach(Assembly loadedAssembly in AppDomain.CurrentDomain.GetAssemblies())
    if (loadedAssembly.FullName == "foobar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
    	assembly = loadedAssembly;

if(assembly == null)
{
    byte[] studybin = System.IO.File.ReadAllBytes(@"C:pathToAssemblyfoobar.dll");
    assembly = Assembly.Load(studybin);                
}

Note that if you are trying to find a specific assembly in a directory, you can run 'System.Reflection.AssemblyName.GetAssemblyName(path);' to see if the FullName matches what you are looking for. 'GetAssemblyName(path)' does NOT inject the assembly into your current AppDomain.

Also note that this solution is not appropriate for applications that must only rarely restart AND the assemblies change with high frequency. Every time an assembly is loaded, the memory footprint of you application will grow. There is no method to unload an assembly, thus the only option to shrink memory usage is to restart the application. However, this limitation is often preferable to the large performance, memory, and code complexity overhead of using multiple app domains. This limitation is also unavoidable if you wish to work with Types.