좋아, 우리는 몇 가지를 분명히해야합니다. 로드하고 iteslf을 파일을 잠그지 않고 다른 응용 프로그램 도메인에 DLL을 언로드 할 수 있도록하려면 첫째, 어쩌면이 같은 방법을 사용할 수 있습니다
AppDomain apd = AppDomain.CreateDomain("newdomain");
using(var fs = new FileStream("myDll.dll", FileMode.Open))
{
var bytes = new byte[fs.Length];
fs.Read(bytes, 0, bytes .Length);
Assembly loadedAssembly = apd.Load(bytes);
}
이 방법을, 파일 잠금 및되지 않습니다 나중에 도메인을 언로드하고 파일을 다시 컴파일하고 나중에 최신 버전으로로드 할 수 있어야합니다. 그러나 이것이 귀하의 응용 프로그램을 깰 수없는 경우 100 % 확실하지 않습니다.
두 번째 이유 때문입니다. MSDN에 따라 CreateInstanceAndUnwrap
메서드를 사용하는 경우 두 appdomains (호출중인 호출과 호출중인 호출)에 어셈블리를로드해야합니다. 그리고 AppDomains에로드 된 두 개의 다른 dll이있을 때 상황이 끝날 수 있습니다.
The assembly that contains unwrapped class must be loaded into both application domains, but it can load other assemblies that exist only in the new application domain.
지금은 기억하지 않는다,하지만 난 당신이 CreateInstanceAndUnwrap
를 호출 할 때 두 응용 프로그램 도메인에있는 객체 생성의 동작이 다를 수 있다고 생각하지만, 나는 세부 사항을 기억하지 않습니다.
플러그인 아키텍처의 경우이 블로그 게시물을 읽을 수 있습니다. About how to handle Dynamic Plugins using the AppDomain Class to Load and Unload Code
나는이 작품을 응용 프로그램 도메인과 내가 약간의 혼동을 소개하는 방법을 잊어
편집 할 수 있습니다. 나는 '플러그인'아키텍처가 어떻게 작동 할 수 있는지에 대한 간단한 예를 준비했다. 그것은 이전에 넣어 둔 블로그에서 설명한 것과 매우 흡사합니다. 여기에 Shadow Copying을 사용하는 샘플이 있습니다. 어떤 이유로 든 사용하지 않으려한다면 사용하기 쉽게 변경할 수 있습니다. AppDomain.Load(byte[] bytes)
3 개의 어셈블리가 있습니다. 첫 번째 어셈블리는 기본 플러그인 어셈블리이며, 프록시로 작동하며로드됩니다. 모든 AppDomains (우리의 경우 - 기본 앱 도메인 및 플러그인 앱 도메인에 있음).
여기서 우리는 SamplePlugin.dll이라는 더미 플러그인으로 어셈블리를 만들고 "Plugins"폴더에 저장합니다. 그것은 PluginBaseLib.dll가
그림자 복사가 매우 편리 할 것으로 보인다
namespace SamplePlugin
{
public class MySamplePlugin : MyPluginBase
{
public MySamplePlugin()
{ }
public override void DrawingControl()
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("----------------------");
Console.WriteLine("This was called from app domian {0}", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("I have following assamblies loaded:");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Console.WriteLine("\t{0}", assembly.GetName().Name);
}
Console.WriteLine("----------------------");
Console.ForegroundColor = color;
}
}
}
만 PluginBaseLib.dll를 참조합니다 마지막 조립 (간단한 콘솔 응용 프로그램) 및
namespace ConsoleApplication1
{
//'Default implementation' which doesn't use any plugins. In this sample
//it just lists the assemblies loaded in AppDomain and AppDomain name itself.
public static void DrawControlsDefault()
{
Console.WriteLine("----------------------");
Console.WriteLine("No custom plugin, default app domain {0}", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("I have following assamblies loaded:");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Console.WriteLine("\t{0}", assembly.GetName().Name);
}
Console.WriteLine("----------------------");
}
class Program
{
static void Main(string[] args)
{
//Showing that we don't have any additional plugins loaded in app domain.
DrawControlsDefault();
var appDir = AppDomain.CurrentDomain.BaseDirectory;
//We have to create AppDomain setup for shadow copying
var appDomainSetup = new AppDomainSetup
{
ApplicationName = "", //with MSDN: If the ApplicationName property is not set, the CachePath property is ignored and the download cache is used. No exception is thrown.
ShadowCopyFiles = "true",//Enabling ShadowCopy - yes, it's string value
ApplicationBase = Path.Combine(appDir,"Plugins"),//Base path for new app domain - our plugins folder
CachePath = "VSSCache"//Path, where we want to have our copied dlls store.
};
var apd = AppDomain.CreateDomain("My new app domain", null, appDomainSetup);
//Loading dlls in new appdomain - when using shadow copying it can be skipped,
//in CreatePlugin method all required assemblies will be loaded internaly,
//Im using this just to show how method can be called in another app domain.
//but it has it limits - method cannot return any values and take any parameters.
//apd.DoCallBack(new CrossAppDomainDelegate(MyPluginsHelper.LoadMyPlugins));
//We are creating our plugin proxy/factory which will exist in another app domain
//and will create for us objects and return their remote 'copies'.
var proxy = (MyPluginFactory) apd.CreateInstance("PluginBaseLib", "PluginBaseLib.MyPluginFactory").Unwrap();
//if we would use here method (MyPluginBase) apd.CreateInstance("SamplePlugin", "SamplePlugin.MySamplePlugin").Unwrap();
//we would have to load "SamplePlugin.dll" into our app domain. We may not want that, to not waste memory for example
//with loading endless number of types.
var instance = proxy.CreatePlugin("SamplePlugin", "SamplePlugin.MySamplePlugin");
instance.DrawingControl();
Console.WriteLine("Now we can recompile our SamplePlugin dll, replace it in Plugin directory and load in another AppDomain. Click Enter when you ready");
Console.ReadKey();
var apd2 = AppDomain.CreateDomain("My second domain", null, appDomainSetup);
var proxy2 = (MyPluginFactory)apd2.CreateInstance("PluginBaseLib", "PluginBaseLib.MyPluginFactory").Unwrap();
var instance2 = proxy2.CreatePlugin("SamplePlugin", "SamplePlugin.MySamplePlugin");
instance2.DrawingControl();
//Now we want to prove, that this additional assembly was not loaded to prmiary app domain.
DrawControlsDefault();
//And that we still have the old assembly loaded in previous AppDomain.
instance.DrawingControl();
//App domain is unloaded so, we will get exception if we try to call any of this object method.
AppDomain.Unload(apd);
try
{
instance.DrawingControl();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
}
}를 참조있다.
잠금없이 어셈블리를로드하려면 섀도 복사본을 사용하는 것이 더 좋습니다 (http://msdn.microsoft.com/en-us/library/ms404279.aspx). – Maarten
나는 당신의 예제에 대해서 궁금해한다. 기본 지식이 부족하기 때문이다 ... 새로운'loadedAssembly'를 디폴트 최상위 레벨이 아닌'apd' AppDomain에 "적용"할 것인가? AppDomain을 생성 한 것처럼 순서대로 암시되어 있습니까? 그러면 Unload()가 실행될 때까지 그 아래에있는 모든 것이 AppDomain의 일부가됩니다. 또한, 훌륭한 기사, 내 머리 위로 조금. 나는 그것의 일부를 찢어 버리고 광고 사이트에 올려 놓았으나 전체 기사를 갖는 것이 좋다. 나는 오늘부터 그 과정을 통해 정말로 배우려고 노력할 것입니다. 그것이 기능적인 소스 파일을 가지기를 바란다. – Adam
귀하의 질문을 이해하는 경우 모르겠지만, 나는 예전의 예전 응용 프로그램에서 몇 가지 예와 의견을 가지고 놀아 보려고합니다. –