2014-09-26 44 views
2

我一直在研究這幾天。我試圖在它自己的AppDomain下的外部程序集中正確地創建一個類的實例。在新的AppDomain下執行一個dll程序集

我已經能夠在新的AppDomain下加載外部程序集,但是它的所有依賴似乎都在父AppDomain中加載,這會破壞目的,因爲我想稍後卸載dll以釋放對它們的鎖定(插件系統)。任何想法,爲什麼它會這樣做?

public MyCustomObject BindAssembly() 
{ 
    string currentAssemblyPath = @"C:\PathToMy\Assembly"; 
    string currentAssemblyFile = @"C:\PathToMy\Assembly\MyAssembly.dll"; 
    AssemblyName currentAssemblyName = AssemblyName.GetAssemblyName(currentAssemblyFile); 
    AppDomain domain = AppDomain.CurrentDomain; 
    domain.AssemblyResolve += domain_AssemblyResolve; 
    AppDomainSetup setup = new AppDomainSetup() 
    { 
     PrivateBinPath = currentAssemblyPath, 
     ApplicationBase = domain.BaseDirectory, 
     DynamicBase = domain.SetupInformation.DynamicBase, 
     ShadowCopyFiles = domain.SetupInformation.ShadowCopyFiles, 
     CachePath = domain.SetupInformation.CachePath, 
     AppDomainManagerAssembly = domain.SetupInformation.AppDomainManagerAssembly, 
     AppDomainManagerType = domain.SetupInformation.AppDomainManagerType 
    }; 
    AppDomain newDomain = AppDomain.CreateDomain("NewDomain", AppDomain.CurrentDomain.Evidence, setup); 
    newDomain.AssemblyResolve += newDomain_AssemblyResolve; 

    currentAssembly = newDomain.Load(currentAssemblyName); 
    // tried this too 
    //var obj = domain.CreateInstanceFromAndUnwrap(currentAssemblyFile, className); 

    // list all of the assemblies inside the custom app domain 
    var newDomainAssemblies = newDomain.GetAssemblies(); // (contains my loaded assembly, but not dependencies) 

    // list all of the assemblies inside the parent app domain 
    var appAssemblies = AppDomain.CurrentDomain.GetAssemblies(); // (contains my loaded assembly as well as all dependencies) 

    return obj as MyCustomObject; 
} 

// resolve dependencies in custom domain 
Assembly newDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    // this never fires 
    AppDomain domain = (AppDomain)sender; 
} 

// resolve dependencies in parent domain 
Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    AppDomain domain = (AppDomain)sender; 
    string assemblyDependencyPath = String.Format(@"{0}", Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(args.RequestingAssembly.CodeBase).Path))); 
    string[] files = Directory.GetFiles(assemblyDependencyPath, "*.dll", SearchOption.AllDirectories); 
    foreach (string file in files) 
    { 
     // if we found it, load the assembly and cache it. 

     AssemblyName aname = AssemblyName.GetAssemblyName(file); 
     if (aname.FullName.Equals(args.Name)) 
     { 
      Assembly assembly = domain.Load(aname); 
      //Assembly assembly = Assembly.LoadFrom(file); // also tried this, same result 
      return assembly; 
     } 
    } 
} 
+0

之間傳遞你試過'currentAssembly = newDomain.Load(currentAssemblyName);'而不是'currentAssembly = domain.Load(currentAssemblyName);'? – Rhumborl 2014-09-26 21:39:53

+0

我還確認,如果我卸載了我創建的新AppDomain,相關程序集仍然保留在父AppDomain中。 – 2014-09-26 21:39:54

+0

Rhumborl - 我很抱歉,這是我的存根代碼中的一個錯字。修正了我的問題。 – 2014-09-26 21:40:43

回答

1

我不知道如何(或一般跨AppDomain的)將與抽象類的不同實現的工作,因爲你可能會發現的依賴性仍然需要使用子類在主AppDomain ,但最近我不得不做了類似的事情,發現使用與MyCustomObject相同的程序集中的Serializable Loader類是使事物分離的最佳方法。

這個想法是,在當前AppDomain中創建加載程序,然後編組到新的0123',並要求加載和實例化所需的程序集和類型。

注意,無論是裝載機和任何從MyCustomObject繼承必須是SerializableMarshalByRefObject繼承,因爲他們將在AppDomain小號

public MyCustomObject BindAssembly() 
{ 
    string currentAssemblyPath = @"C:\PathToMy\Assembly"; 
    string currentAssemblyFile = @"C:\PathToMy\Assembly\MyAssembly.dll"; 
    AssemblyName currentAssemblyName = AssemblyName.GetAssemblyName(currentAssemblyFile); 
    AppDomain domain = AppDomain.CurrentDomain; 
    domain.AssemblyResolve += domain_AssemblyResolve; 
    AppDomainSetup setup = new AppDomainSetup() 
    { 
     PrivateBinPath = currentAssemblyPath, 
     ApplicationBase = domain.BaseDirectory, 
     DynamicBase = domain.SetupInformation.DynamicBase, 
     ShadowCopyFiles = domain.SetupInformation.ShadowCopyFiles, 
     CachePath = domain.SetupInformation.CachePath, 
     AppDomainManagerAssembly = domain.SetupInformation.AppDomainManagerAssembly, 
     AppDomainManagerType = domain.SetupInformation.AppDomainManagerType 
    }; 

    AppDomain newDomain = AppDomain.CreateDomain("NewDomain", AppDomain.CurrentDomain.Evidence, setup); 

    newDomain.Load(typeof(Loader).Assembly.GetName()); 

    Loader loader = (Loader)newDomain.CreateInstanceAndUnwrap(
     typeof(Loader).Assembly.FullName, typeof(Loader).FullName); 

    // load the assembly containing MyCustomObject into the remote domain 
    loader.LoadAssembly(currentAssemblyFile); 

    // ask the Loader to create the object instance for us 
    MyCustomObject obj = loader.CreateCustomObject(); 

    return obj; 
} 

public class Loader : MarshalByRefObject 
{ 
    /// <summary>Stores the assembly containing the task class.</summary> 
    private Assembly assembly; 

    /// <summary>Retrieves the current lifetime service object that controls the lifetime policy for this instance.</summary> 
    /// <returns>This always returns null.</returns> 
    public override object InitializeLifetimeService() 
    { 
     return null; 
    } 

    /// <summary>Loads the assembly containing the task class.</summary> 
    /// <param name="path">The full path to the assembly DLL containing the task class.</param> 
    public void LoadAssembly(string path) 
    { 
     this.assembly = Assembly.Load(AssemblyName.GetAssemblyName(path)); 
    } 

    /// <summary>Instantiates the required object.</summary> 
    /// <param name="classFullName">The full name (namespace + class name) of the task class.</param> 
    /// <returns>The new object.</returns> 
    public MyCustomObject CreateCustomObject() 
    { 
     MyCustomObject instance = new MyCustomObject(); 
     // do whatever you want with the instance here 
     return instance; 
    } 
} 
+0

我的確使用代理嘗試類似於此,但是我重新編寫了它來匹配您的建議,但在此處無法加載組裝錯誤: 加載程序加載程序=(Loader)domain.CreateInstanceFromAndUnwrap(typeof(Loader).Assembly.FullName,typeof(Loader).FullName); – 2014-09-26 23:38:27

+0

經過一番搗鼓之後,我意識到我必須將CreateInstanceFromAndUnwrap()傳遞給dll的完整路徑,但行爲依然存在,即將依賴關係添加到父AppDomain中。 – 2014-09-27 00:17:14

相關問題