简体   繁体   English

将当前程序集加载到不同的AppDomain中

[英]Load Current Assembly into different AppDomain

I have created an AppDomain with a different base directory. 我创建了一个具有不同基目录的AppDomain However, I cannot seem to load the currently executing assembly into the other AppDomain without having a copy of the current executing assembly in the base directory. 但是,我似乎无法将当前正在执行的程序集加载到其他AppDomain中,而没有基本目录中当前正在执行的程序集的副本。 I've even tried to load it from the bytes. 我甚至试图从字节加载它。

I get no exception when I try to load, but when I try to use: 我尝试加载时没有异常,但是当我尝试使用时:

domain.DoCallBack(new CrossAppDomainDelegate(... 

I get: 我明白了:

Could not load file or assembly ........... The system cannot find the file specified. 无法加载文件或程序集............系统找不到指定的文件。

My code is as follows: 我的代码如下:

private static void SaveAssemblies(Assembly ass, List<byte[]> assemblyByteList)
{
    AssemblyName[] assNames = ass.GetReferencedAssemblies();
    foreach (AssemblyName assName in assNames)
    {
        Assembly referedAss = Assembly.Load(assName);
        if (!referedAss.GlobalAssemblyCache)
        {
            SaveAssemblies(referedAss, assemblyByteList);
        }
    }
    byte[] rawAssembly = File.ReadAllBytes(ass.Location);
    assemblyByteList.Add(rawAssembly);
}

public static AppDomain CreateAppDomain(string dir, string name)
{
    AppDomainSetup domainSetup = new AppDomainSetup();
    domainSetup.ApplicationBase = dir;
    domainSetup.ApplicationName = Path.GetFileName(dir);
    domainSetup.PrivateBinPath = Path.Combine(dir, "Libs");

    AppDomain domain = AppDomain.CreateDomain(name, null, domainSetup);
    //Load system assemblies needed for the module
    List<byte[]> assemblyByteList = new List<byte[]>();
    SaveAssemblies(Assembly.GetExecutingAssembly(), assemblyByteList);

    foreach (byte[] rawAssembly in assemblyByteList)
        domain.Load(rawAssembly);

    domain.DoCallBack(new CrossAppDomainDelegate(SetupLogging));
    return domain;
}

Update: 更新:

It seems the assembly is loaded if i look in output i see this 如果我查看输出,看起来组件已加载我看到了这一点

'TaskExecuter.Terminal.vshost.exe' (Managed (v4.0.30319)): Loaded 'NLog' 'TaskExecuter.Terminal.vshost.exe' (Managed (v4.0.30319)): Loaded 'TaskExecuter', Symbols loaded. 'TaskExecuter.Terminal.vshost.exe'(Managed(v4.0.30319)):已加载'NLog''TaskExecuter.Terminal.vshost.exe'(托管(v4.0.30319)):已加载'TaskExecuter',已加载符号。

but i still get the exception... i don't understand this 但我仍然得到例外......我不明白这一点

System.IO.FileNotFoundException was unhandled Message=Could not load file or assembly 'TaskExecuter, Version=1.0.4244.31921, Culture=neutral, PublicKeyToken=null' or one of its dependencies. System.IO.FileNotFoundException未处理Message =无法加载文件或程序集'TaskExecuter,Version = 1.0.4244.31921,Culture = neutral,PublicKeyToken = null'或其依赖项之一。 The system cannot find the file specified. 该系统找不到指定的文件。 Source=mscorlib 来源= mscorlib程序
FileName=TaskExecuter, Version=1.0.4244.31921, Culture=neutral, PublicKeyToken=null FusionLog==== Pre-bind state information === LOG: User = Peter-PC\\Peter LOG: DisplayName = TaskExecuter, Version=1.0.4244.31921, Culture=neutral, PublicKeyToken=null (Fully-specified) LOG: Appbase = file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks LOG: Initial PrivatePath = C:\\ProgramData\\TaskExecuter\\TaskLib\\uTorrentTasks\\Libs Calling assembly : (Unknown). FileName = TaskExecuter,Version = 1.0.4244.31921,Culture = neutral,PublicKeyToken = null FusionLog ====预绑定状态信息===日志:User = Peter-PC \\ Peter LOG:DisplayName = TaskExecuter,Version = 1.0.4244.31921 ,Culture = neutral,PublicKeyToken = null(完全指定)日志:Appbase = file:/// C:/ ProgramData / TaskExecuter / TaskLib / uTorrentTasks日志:初始PrivatePath = C:\\ ProgramData \\ TaskExecuter \\ TaskLib \\ uTorrentTasks \\ Libs调用汇编:(未知)。 === LOG: This bind starts in default load context. ===日志:此绑定在默认加载上下文中启动。 LOG: Using application configuration file: d:\\users\\peter\\documents\\visual studio 2010\\Projects\\TaskExecuter\\TaskExecuter.Terminal\\bin\\Release\\TaskExecuter.Terminal.vshost.exe.Config LOG: Using host configuration file: LOG: Using machine configuration file from C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\config\\machine.config. 日志:使用应用程序配置文件:d:\\ users \\ peter \\ documents \\ visual studio 2010 \\ Projects \\ TaskExecuter \\ TaskExecuter.Terminal \\ bin \\ Release \\ TaskExecuter.Terminal.vshost.exe.Config LOG:使用主机配置文件:LOG:使用C:\\ Windows \\ Microsoft.NET \\ Framework \\ v4.0.30319 \\ config \\ machine.config中的计算机配置文件。 LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). 日志:此时策略未应用于引用(私有,自定义,部分或基于位置的程序集绑定)。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter.DLL. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter.DLL。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter/TaskExecuter.DLL. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter/TaskExecuter.DLL。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter.DLL. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter.DLL。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter/TaskExecuter.DLL. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter/TaskExecuter.DLL。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter.EXE. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter.EXE。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter/TaskExecuter.EXE. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter/TaskExecuter.EXE。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter.EXE. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter.EXE。 LOG: Attempting download of new URL file:///C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter/TaskExecuter.EXE. 日志:尝试下载新的URL文件:/// C:/ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter/TaskExecuter.EXE。

StackTrace: at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks) at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) at System.Reflection.Assembly.Load(String assemblyString) at System.Runtime.Serialization.FormatterServices.LoadAssemblyFromSt StackTrace:System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName,String codeBase,System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName,String codeBase,Evidence assemblySecurity,RuntimeAssembly locationHint,StackCrawlMark&stackMark,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks))证据assemblySecurity,RuntimeAssembly locationHint,StackCrawlMark&stackMark,Boolean throwOnFileNotFound,Boolean forIntrospection,Boolean suppressSecurityChecks)System.Reflection.RuntimeAssembly.InternalLoad的System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef,Evidence assemblySecurity,StackCrawlMark&stackMark,Boolean forIntrospection,Boolean suppressSecurityChecks) (String assemblyString,Evidence assemblySecurity,StackCrawlMark&stackMark,Boolean forIntrospection)在System.Runtime.Serialization.FormatterServices.LoadAssemblyFromSt上的System.Reflection.Assembly.Load(String assemblyString)处。 ring(String assemblyName) at System.Reflection.MemberInfoSerializationHolder..ctor(SerializationInfo info, StreamingContext context) at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate) at TaskExecuter.AppDomainHelper.CreateAppDomain(String dir, String name) in d:\\users\\peter\\documents\\visual studio 2010\\Projects\\TaskExecuter\\TaskExecuter\\AppDomainHelper.cs:line 50 at TaskExecuter.TaskManagment.TaskFinder.Probe() in d:\\users\\peter\\documents\\visual studio 2010\\Projects\\TaskExecuter\\TaskExecuter\\TaskManagment\\TaskFinder.cs:line 29 at TaskExecuter.TaskManagment.TaskManager.LoadTasks() in d:\\users\\peter\\documents\\visual studio 2010\\Projects\\TaskExecuter\\TaskExecuter\\TaskManagment\\TaskManager.cs:line 63 at TaskExecuter.TaskManagment.TaskManager.Start() in d:\\users\\peter\\documents\\visual studio 2010\\Projects\\TaskExecuter\\TaskExecuter\\TaskManagment\\TaskManager.cs:line 95 at TaskExecuter.Terminal.Program.Main(String[] args) in d:\\users\\peter\\documents\\visual studio 2010\\Proj 位于System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)的System.Reflection.MemberInfoSerializationHolder..ctor(SerializationInfo info,StreamingContext context)中的ring(String assemblyName)位于d:\\ users \\中的TaskExecuter.AppDomainHelper.CreateAppDomain(String dir,String name) peter \\ documents \\ visual studio 2010 \\ Projects \\ TaskExecuter \\ TaskExecuter \\ AppDomainHelper.cs:D:\\ users \\ peter \\ documents \\ visual studio 2010 \\ Projects \\ TaskExecuter \\ TaskExecuter \\中的TaskExecuter.TaskManagment.TaskFinder.Probe()第50行TaskManagment \\ TaskFinder.cs:位于TaskExecuter.TaskManagment的d:\\ users \\ peter \\ documents \\ visual studio 2010 \\ Projects \\ TaskExecuter \\ TaskExecuter \\ TaskManagment \\ TaskManager.cs:第63行的TaskExecuter.TaskManagment.TaskManager.LoadTasks()第29行d:\\ users \\ peter \\ documents \\ visual studio 2010中的.TaskManager.Start()\\ Projects \\ TaskExecuter \\ TaskExecuter \\ TaskManagment \\ TaskManager.cs:d中的TaskExecuter.Terminal.Program.Main(String [] args)中的第95行:\\ users \\ peter \\ documents \\ visual studio 2010 \\ Proj ects\\TaskExecuter\\TaskExecuter.Terminal\\Program.cs:line 16 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() ects \\ TaskExecuter \\ TaskExecuter.Terminal \\ Program.cs:System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly,String [] args)的第16行,位于Microsoft的System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)。 System.Threading.ExecutionContext.Run上System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean ignoreSyncCtx)的System.Threading.ThreadPel.ThreadStart_Context(Object state)中的VisualStudio.HostingProcess.HostProc.RunUsersAssembly() System.Threading.ThreadHelper.ThreadStart()中的(ExecutionContext executionContext,ContextCallback回调,对象状态)
InnerException: 的InnerException:

I was able to recover the linked to blog post using archive.org and also come up with a working solution. 我能够使用archive.org恢复链接到博客文章,并提出了一个可行的解决方案。

My goal was to dynamically compile an exe into a temporary location, and then have that exe shadow load all main dlls in a child appdomain so that the main application that spawned the exe can be updated easily. 我的目标是动态地将exe编译到临时位置,然后让exe阴影加载子appdomain中的所有主dll,以便可以轻松更新生成exe的主应用程序。 The basic approach is using childAppDomain.CreateInstanceFrom to create a type that in the constructor installs the assembly resolve event handler. 基本方法是使用childAppDomain.CreateInstanceFrom创建一个在构造函数中安装程序集解析事件处理程序的类型。 My code looked like 我的代码看起来像

var exportAppDomain = AppDomain.CreateDomain(
    runnerName,
    null,
    appDomainSetup,
    new PermissionSet(PermissionState.Unrestricted));

exportAppDomain.CreateInstanceFrom(
    Assembly.GetExecutingAssembly().Location,
    "ExportLauncher.AppDomainResolver",
    true,
    BindingFlags.Public | BindingFlags.Instance,
    null,
    new object[] { Assembly.GetExecutingAssembly().Location },
    null,
    null);

And the type that creates the needed AssemblyResolve handler (the blog post below describes why you need another type) 以及创建所需AssemblyResolve处理程序的类型(下面的博客文章描述了为什么需要其他类型)

class AppDomainResolver
{
    string _sourceExeLocation;

    public AppDomainResolver(string sourceExeLocation)
    {
        _sourceExeLocation = sourceExeLocation;
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }

    Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (args.Name.Contains("exporterLauncher")) // why does it not already know it has this assembly loaded? the seems to be required
            return typeof(AppDomainResolver).Assembly;
        else
            return null;
    }
}

Here is the original blog post: 这是原始博文:

Application Domains is hard… 应用域很难......

Have you ever been working with Application Domain in .NET?, in the beginning it doesn't seem all that difficult, but ones you get to know them you begin to realize all the little difficulties. 你有没有在.NET中使用Application Domain?一开始看起来并不那么困难,但是你了解它们就会开始意识到所有的困难。

Everything works fine as long as you don't move outside the Host AppDomains.BaseDirectory, but in our case we wanted to have Plug-ins deployed at say location “C:\\My Plug-ins” while the host application would run at “C:\\Program Files\\My App”, since we might run into dependencies from the AppDomain to some of the Host Assemblies problems was apparently inevitable. 只要您不移动到Host AppDomains.BaseDirectory之外,一切正常,但在我们的情况下,我们希望在主机应用程序运行的“C:\\ My Plug-ins”位置部署插件C:\\ Program Files \\ My App“,因为我们可能会遇到从AppDomain到某些主机程序集的依赖关系,这显然是不可避免的。

The Classic Here is some simple code and our first attempt. 经典这是一些简单的代码和我们的第一次尝试。

 1:  string applicationBase = Path.GetDirectoryName(interOperabilityPackageType.AssemblyDescription.AssemblyPath);
   2:  AppDomainSetup setup = new AppDomainSetup
   3:  {
   4:      ApplicationName = name,
   5:      ApplicationBase = applicationBase,
   6:      PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory,
   7:      PrivateBinPathProbe = AppDomain.CurrentDomain.BaseDirectory,
   8:      ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
   9:  };
  10:   
  11:  Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
  12:  AppDomain domain = AppDomain.CreateDomain(name, evidence, setup);

Seems very simple, but because “ApplicationBase” is different from “AppDomain.CurrentDomain.BaseDirectory” we ran into what seems to be a very well know exception. 看起来很简单,但因为“ApplicationBase”与“AppDomain.CurrentDomain.BaseDirectory”不同,我们遇到了一个看似非常熟悉的异常。

System.IO.FileNotFoundException: Could not load file or assembly 'Host.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. System.IO.FileNotFoundException:无法加载文件或程序集“Host.Services,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”或其依赖项之一。 The system cannot find the file specified. 该系统找不到指定的文件。

If you have worked with any sort of dynamically loading assemblies I am fairly sure that is familiar to you. 如果您使用过任何类型的动态加载程序集,我相信您很熟悉。 And the issue is that “Host.Services” was know within the Host Application Domain because it is stored in “C:\\Program Files\\My App”, and the Application Domain looking for it is looking in “C:\\My Plug-ins”. 问题是“Host.Services”在Host Application Domain中是已知的,因为它存储在“C:\\ Program Files \\ My App”中,而寻找它的Application Domain正在查看“C:\\ My Plug-插件”。

Well we Thought we instructed it to also look in “AppDomain.CurrentDomain.BaseDirectory” which would be “C:\\Program Files\\My App”, but that was not the case. 好吧,我们以为我们指示它也会查看“AppDomain.CurrentDomain.BaseDirectory”,这将是“C:\\ Program Files \\ My App”,但事实并非如此。

AppDomain.AssemblyResolve to the rescue? AppDomain.AssemblyResolve救援? Ok so we have been working with these quirks before, so we knew how we could use “AppDomain.AssemblyResolve” to manually resolve any assemblies that the AppDomain it self could not handle. 好的,所以我们之前一直在使用这些怪癖,所以我们知道如何使用“AppDomain.AssemblyResolve”手动解析它自己无法处理的AppDomain的任何程序集。

1:  string applicationBase = Path.GetDirectoryName(interOperabilityPackageType.AssemblyDescription.AssemblyPath);
   2:  AppDomainSetup setup = new AppDomainSetup
   3:  {
   4:      ApplicationName = name,
   5:      ApplicationBase = applicationBase,
   6:      PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory,
   7:      PrivateBinPathProbe = AppDomain.CurrentDomain.BaseDirectory,
   8:      ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
   9:  };
  10:   
  11:  Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
  12:  AppDomain domain = AppDomain.CreateDomain(name, evidence, setup);
  13:  domain.AssemblyResolve += Resolve;

That should work right, well we thought so and ones again we were wrong, what happens now is that instead of actually getting as far as initializing the Application Domain and using it, instead it fails right where we hooked up the event handler for resolving assemblies. 这应该是正确的,我们是这么认为的,而我们又错了,现在发生的事情是,实际上不是初始化应用程序域并使用它,而是在我们连接事件处理程序以解析程序集的地方失败了。

Again the exception looks very much like the previous mentioned, but this time it can't find the Assembly that contains the Type that has the “Resolve” handler we set up in the very last line in the above snippet. 同样异常看起来非常像前面提到的那样,但是这次它找不到包含Type的组件,它具有我们在上面代码片段的最后一行中设置的“Resolve”处理程序。

AppDomain.Load then! AppDomain.Load然后! Ok, so obviously when hooking up the event handler, the Application Domain needs to know the Type of the object handling that event, that is actually fairly understandable when you think about it, so if the Application Domain can't even find that one and load we can't really handle anything. 好吧,很明显在连接事件处理程序时,Application Domain需要知道处理该事件的对象的类型,当你考虑它时实际上是可以理解的,所以如果Application Domain甚至找不到那个,加载我们无法真正处理任何事情。

So what is next? 接下来是什么? Our idea was to manually instruct the Application Domain to load a shallow assembly that didn't have any other dependencies that what could be found in the GAC, and the hook an event handler up. 我们的想法是手动指示Application Domain加载一个浅组件,该组件没有任何其他依赖关系,可以在GAC中找到,并挂钩一个事件处理程序。

 1:  string applicationBase = Path.GetDirectoryName(interOperabilityPackageType.AssemblyDescription.AssemblyPath);
   2:  AppDomainSetup setup = new AppDomainSetup
   3:  {
   4:      ApplicationName = name,
   5:      ApplicationBase = applicationBase,
   6:      PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory,
   7:      PrivateBinPathProbe = AppDomain.CurrentDomain.BaseDirectory,
   8:      ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
   9:  };
  10:   
  11:  Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
  12:  AppDomain domain = AppDomain.CreateDomain(name, evidence, setup);
  13:  domain.Load(File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Host.AssemblyLoader.dll")));
  14:  domain.AssemblyResolve += new AssemblyLoader(AppDomain.CurrentDomain.BaseDirectory).Handle;

Using a very simple little class like the following, and don't mind the odd Resolve behavior. 使用一个非常简单的小类,如下所示,并不介意奇怪的Resolve行为。

 1:  [Serializable]
   2:  public class AssemblyLoader
   3:  {
   4:      private string ApplicationBase { get; set; }
   5:   
   6:      public AssemblyLoader(string applicationBase)
   7:      {
   8:          ApplicationBase = applicationBase;
   9:      }
  10:   
  11:      public Assembly Resolve(object sender, ResolveEventArgs args)
  12:      {
  13:          AssemblyName assemblyName = new AssemblyName(args.Name);
  14:          string fileName = string.Format("{0}.dll", assemblyName.Name);
  15:          return Assembly.LoadFile(Path.Combine(ApplicationBase, fileName));
  16:      }
  17:  }

So yes or no?… NO!… same problem still. 那么是或否?...不!......同样的问题仍然存在。

Things are much more simple! 事情要简单得多! Actually things became much more simple in the end when we managed to make it work. 实际上,当我们设法使其工作时,事情变得更加简单。

I Can't say how exactly the .NET team has envisioned that this should work, we couldn't really find out any useable things that the “PrivateBinPath” and “PrivateBinPathProbe” was used for. 我不能说.NET团队究竟如何设想这应该有效,我们无法找到“PrivateBinPath”和“PrivateBinPathProbe”用于的任何可用的东西。 Well we use them now, and made them work as we expected they would! 好吧,我们现在就使用它们,让它们像我们预期的那样工作!

So we changed the “AssemblyLoader” class to look like this instead: 所以我们改为将“AssemblyLoader”类改为:

   1:  [Serializable]
   2:  public class AssemblyLoader : MarshalByRefObject
   3:  {
   4:      private string ApplicationBase { get; set; }
   5:   
   6:      public AssemblyLoader()
   7:      {
   8:          ApplicationBase = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
   9:          AppDomain.CurrentDomain.AssemblyResolve += Resolve;
  10:      }
  11:   
  12:      private Assembly Resolve(object sender, ResolveEventArgs args)
  13:      {
  14:          AssemblyName assemblyName = new AssemblyName(args.Name);
  15:          string fileName = string.Format("{0}.dll", assemblyName.Name);
  16:          return Assembly.LoadFile(Path.Combine(ApplicationBase, fileName));
  17:      }
  18:  }

So rather than hooking up the event where we created the Application Domain, we let the class do it by it self, and to “CurrentDomain” instead. 因此,我们不是将我们创建应用程序域的事件挂钩,而是让它自己完成它,而不是“CurrentDomain”。

Ok so wait, doesn't that cause an issue when creating it in the factory since it is now loading for the wrong domain? 好吧等等,这不会导致在工厂中创建它时出现问题,因为它现在正在加载错误的域名吗? Well thankfully you are able to create objects within domains from the outside. 谢天谢地,您可以从外部在域内创建对象。

So creating the domain is now done as follows: 因此,现在按如下方式创建域:

1:  string applicationBase = Path.GetDirectoryName(interOperabilityPackageType.AssemblyDescription.AssemblyPath);
   2:  AppDomainSetup setup = new AppDomainSetup
   3:  {
   4:      ApplicationName = name,
   5:      ApplicationBase = applicationBase,
   6:      PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory,
   7:      PrivateBinPathProbe = AppDomain.CurrentDomain.BaseDirectory,
   8:      ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
   9:  };
  10:   
  11:  Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
  12:  AppDomain domain = AppDomain.CreateDomain(name, evidence, setup);
  13:  domain.CreateInstanceFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Host.AssemblyLoader.dll"),"Host.AssemblyLoader");

We don't even care for maintaining a reference to the “AssemblyLoader” since it should pretty much be kept alive by hooking it self up to the Event. 我们甚至不关心维护对“AssemblyLoader”的引用,因为它应该通过将它自己挂钩到事件来保持活着。

Hopefully this can help some that has stumbled over the same problem, I see many workarounds where people then either just let Plug-ins be installed in same host directory, having all the necessary dependencies deployed along with the plug-in even though it isn't something the plug-in knows it is dependant on and so forth. 希望这可以帮助那些偶然发现同样问题的人,我看到很多解决方法,然后人们要么只是让插件安装在同一个主机目录中,并且随着插件一起部署所有必要的依赖项,即使它不是'插件知道它依赖于某些东西等等。

The above at least enables us to install plug-ins away from our host application base which I think is nice. 以上至少使我们能够从我们认为很好的主机应用程序库安装插件。

If anyone have solved this differently, then please make a response, maybe we can find pros and cons in either way, or just discover a better solution. 如果有人以不同的方式解决了这个问题,那么请回复,也许我们可以找到任何方式的优点和缺点,或者只是找到更好的解决方案。

If you have any questions or can't get the above to work, then feel free to ask. 如果您有任何疑问或无法完成上述工作,请随时提出。

author: Jens Melgaard | 作者:Jens Melgaard | posted @ Thursday, July 01, 2010 3:08 PM | 发表于@ Thursday,July 01,2010 3:08 PM | Feedback (0) 反馈(0)

Is there any reason why you do not use the original assemblies ? 您有没有理由不使用原始组件?

So unless your foreign appdomain uses credentials that prevent it from accessing the original assemblies, the method AppDomain.CreateInstanceFromAndUnwrap is capable of doing so. 因此,除非您的外部appdomain使用阻止其访问原始程序集的凭据,否则AppDomain.CreateInstanceFromAndUnwrap方法可以执行此操作。

I suggest you isolate your remotely executed code in a MarshalByRefObject class, using a class like this : 我建议你使用这样的类在MarshalByRefObject类中隔离远程执行的代码:

public class MyRemoteClass : MarshalByRefObject
{
    public void SetupLogging()
    { 
       // ...
    }
}

And use it like this : 并像这样使用它:

var assemblyPath = new Uri(typeof(MyRemoteClass).Assembly.CodeBase).LocalPath;
var remote = (MyRemoteClass)domain.CreateInstanceFromAndUnwrap(assemblyPath, "NameSpace.MyRemoteClass");

remote.SetupLogging();

This will avoid the unnecessary trouble of passing return values via appdomain state, as DoCallBack does not return values. 这将避免通过appdomain状态传递返回值的不必要麻烦,因为DoCallBack不返回值。 This will also avoid mixing AppDomain plumbing code with your application logic. 这也可以避免将AppDomain管道代码与您的应用程序逻辑混合。

Finally, you may need to intercept AppDomain.AssemblyResolve inside MyRemoteClass for other dependencies to load properly, though. 最后,您可能需要拦截MyRemoteClass中的AppDomain.AssemblyResolve,以便正确加载其他依赖项。

Found a solution after loading the assembly from byte setting the .GetName().CodeBase to null resolved the problem... 从字节设置加载程序集后找到一个解决方案.GetName()。CodeBase为null解决了问题...

After looking around i found this page and it has a better solution then mine! 环顾四周后,我找到了这个页面,它有一个更好的解决方案,然后我的!

http://msdn.microsoft.com/en-us/library/aehss7y0.aspx的行为AppDomain.CreateDomain已与.NET4改变,你应该使用http://msdn.microsoft.com/en-us/ library / ms130766.aspx and setup Evidence并“手动” grants ......

My educated guess is that you missed an important part of the error message: 我有根据的猜测是你错过了错误信息的一个重要部分:

System.IO.FileNotFoundException was unhandled Message=Could not load file or assembly 'TaskExecuter, Version=1.0.4244.31921, Culture=neutral, PublicKeyToken=null' or one of its dependencies . System.IO.FileNotFoundException未处理Message =无法加载文件或程序集'TaskExecuter,Version = 1.0.4244.31921,Culture = neutral,PublicKeyToken = null' 或其依赖项之一 The system cannot find the file specified. 该系统找不到指定的文件。 Source=mscorlib 来源= mscorlib程序

Besides not being able to load your assembly from another location than under your ApplicationBase there is probably some dependend assembly missing from where it could be resolved and loaded. 除了无法从ApplicationBase下的其他位置加载程序集之外,可能还有一些dependend程序集从可以解析和加载的地方丢失。

By the way, if you start loading from bytes you should have a look at the assemblies loaded to your domain. 顺便说一句,如果你从字节开始加载,你应该看看加载到你的域的程序集。 The dependend assembly might be loaded already, but the dependency cannot be resolved automatically. 可能已加载dependend程序集,但无法自动解析依赖项。 If you have the same assembly loaded twice, its types will be incompatible. 如果两次加载相同的程序集,则其类型将不兼容。 You'll get funny CastExceptions saying an object of YourClass cannot be cast to YourClass. 你会得到一些有趣的CastExceptions,说无法将YourClass的对象强制转换为YourClass。

You can try to register an AssemblyResolve event handler to your domain, but with this you end up easily with some black magic conjuring stuff from .dll hell. 您可以尝试将AssemblyResolve事件处理程序注册到您的域中,但是使用它可以轻松地使用.dll地狱中的一些黑魔法变形。 If everything else fails and you go to .dll hell yourself, meet me here: Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true 如果其他一切都失败了你去.dll你自己,在这里见到我: 当DisallowApplicationBaseProbing = true时需要连接AssemblyResolve事件

If you need to load assembly yourself avoid loading from bytes... I'd recommend to use at least loading by full assembly path. 如果你需要自己加载程序集,请避免从字节加载......我建议至少使用完整程序集加载。

In general to investigate problems with loading assemblies serach for "fusion log viewer" ( http://www.bing.com/search?q=fussion+log+viewer ) and use the tool to see where code tries to load assemblies from. 一般来说,要研究加载程序集搜索“fusion log viewer”( http://www.bing.com/search?q=fussion+log+viewer )的问题,并使用该工具查看代码尝试从哪里加载程序集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM