Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
164 views
in Technique[技术] by (71.8m points)

c# - How do I implement .net plugins without using AppDomains?

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.

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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
  1. Check if the assembly is already loaded (to avoid memory leaks caused by loading the same assembly over and over again).
  2. If its not loaded, read the assembly into a byte array. This will prevent locking the file.
  3. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...