AppDomain拒绝加载程序集 [英] AppDomain refuses to load an assembly

查看:111
本文介绍了AppDomain拒绝加载程序集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个小的插件框架,并且在AppDomain代码中四处走动,运气不佳.

对我来说最重要的是,我希望在同一类的不同版本之间没有冲突(例如,一个插件可能要使用其自己的Common.dll v 1.0库,而我可能有2.0),这与其他问题类似.

所以我在下面写了这个小应用.

 静态  void  Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault( false );

            Console.WriteLine(Utility.GetVersion());

             var  ads =  AppDomainSetup();
            字符串 appBase =  @" ;
            ads.ApplicationBase = appBase;
            //  ads.PrivateBinPath = appBase; 
            //  ads.ConfigurationFile ="ExtensionLib.dll.config"; 
            //  ads.PrivateBinPathProbe =."; 
             var  ad = AppDomain.CreateDomain(" ,广告);
//  var ah = new AssemblyHelper(); 
//  ad.AssemblyResolve + = ah.MyResolveEventHandler; 
//  ad.AssemblyLoad + = ah.AssemblyLoadedHandler; 

            //  MessageBox.Show(ad.BaseDirectory); 
            组装a = ad.Load(" );
            ILib l =(ILib)a.CreateInstance(" );
            l.DoSomething();

            Console.WriteLine(Utility.GetVersion());
        }
    } 



Common.dll包含实用程序类,但是我们拥有该类的不同版本.插件和主机应用程序都使用相同的ILib(在同一个dll中定义).

主机应用程序设置

c:\....\123
   Common.dll (v 2.0)
   IntegInterface.dll (where ILib is defined, v1.0)
   LoadCommon.exe (the host)



插件应用程序设置

 c:\ .... \ 456
   Common.dll(v 1.0)
   IntegInterface.dll(其中定义了ILib,v1.0)
   ExtensionLib.dll(插件)



当应用运行时,在ad.Load()
时出现异常

System.IO.FileNotFoundException was unhandled
  Message="Could not load file or assembly ''ExtensionLib'' or one of its dependencies. The system cannot find the file specified."
  Source="mscorlib"
  FileName="ExtensionLib"
  FusionLog="Assembly manager loaded from:  C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\mscorwks.dll
  Running under executable  C:\\Users\\Roberto\\Documents\\Visual Studio 2008\\Projects\\LoadCommon\\LoadCommon\\bin\\Debug\\LoadCommon.vshost.exe
  --- A detailed error log follows. \n
  === Pre-bind state information ===
  LOG: User = Roberto-PC\\Roberto
  LOG: DisplayName = ExtensionLib\n (Partial)
  LOG: Appbase = file:///C:/Users/Roberto/Documents/Visual Studio 2008/Projects/LoadCommon/LoadCommon/ExtensionLib/ExtensionLib/bin/Debug
  LOG: Initial PrivatePath = NULL
  Calling assembly : (Unknown).
  ===
  LOG: This bind starts in default load context.
  LOG: Using application configuration file: C:\\Users\\Roberto\\Documents\\Visual Studio 2008\\Projects\\LoadCommon\\LoadCommon\\ExtensionLib\\ExtensionLib\\bin\\Debug\\ExtensionLib.dll.config
  LOG: Using machine configuration file from C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\config\\machine.config.
  LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
  "
  StackTrace:
       at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
       at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
       at System.AppDomain.Load(String assemblyString)
       at System.AppDomain.Load(String assemblyString)
       at LoadCommon.Program.Main() in C:\Users\Roberto\Documents\Visual Studio 2008\Projects\LoadCommon\LoadCommon\Program.cs:line 36
       at System.AppDomain._nExecuteAssembly(Assembly 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)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 



我还尝试设置一个assemblyresolve委托,以查看是否可以提供帮助,但是运气不好,尽管我将AssemblyHelper标记为可序列化,但还是遇到了序列化错误.

在某些时候,我还将使IntegInterface具有不同的版本,并确保我最终会遇到很多问题.

有人可以在这里说些什么吗?非常感谢.

感谢

解决方案

这是关于加载程序集的常见混淆.是否要按其主要可执行模块的文件名加载Assembly?

使用System.Reflection.Assembly.LoadFrom(string fileName).有关其他区别,请参见所有其他System.Reflection.Assembly.Load...方法和帮助页面.该调用应在新创建的Application Domain上下文中完成,而不是在流程的默认(初始)Application Domain中完成.如果我对您的插件组合的假设是错误的,请自由纠正我,我将为您提供一些不同的方法.

 System.AppDomain广告= AppDomain.CreateDomain(" ,广告);
ad.DoCallBack(()= >  {
   //  ... 
   System.Reflection.Assembly.LoadFrom(myPluginFileName);
   //  ... 
}); 



如果您的插件程序集具有入口点(EXE文件),则可以使用System.AppDomain.ExecuteAssembly.我怀疑您是通过这种方式设计插件的(您提到了ILib接口;如果这是您的插件支持的接口,那么,恭喜!这是最好的方法.请参阅下面的参考资料,其中使用特殊的装配属性来选择实现插件接口& mdas;的类,对鲁棒性和性能非常好.
因此,即使我认为您的设计不是基于EXE入口点,但让我展示一下以防万一:

 System.AppDomain广告= AppDomain.CreateDomain(" ,广告);
ad.ExecuteAssembly(myExeFileName); 



很高兴您了解在单独的Application Domain中动态加载插件的重要性,但这仅在以后要卸载它们时才需要.如果您只需要加载一次所有插件,则可以在一个域(默认域)中工作,而不必创建额外的应用程序域.

您可以实现我有关插件程序集和使用Application Domain的各种设计的所有答案:
创建使用可重载插件的WPF应用程序... [ ^ ]
另请参见:
使用CodeDom生成代码 [创建使用可重载插件的WPF应用程序... [ ^ ].

—SA


尝试使用版本,区域性和PublicKeyToken加载程序集

 Assembly.Load
            (" );  pre> 


我需要做的只是打电话,所以尽管SAK的解决方案很有意义(谢谢!),但我还是决定只使用

ILib l = (ILib)ad.CreateInstanceAndUnwrap("ExtensionLib", "ExtensionLib.LibImpl");


做到这一点就好了.此外,我可以更改不同域上的接口,并且它们仍然以某种方式兼容.我确定透明代理会进行一些时髦的跳舞.

谢谢大家!


I''m trying to create a small plugin framework, and have been going around and around the AppDomain code with not much luck.

The most important thing for me is that I want to have no conflicts between different versions of the same class (for example a plugin may want to use its own Common.dll v 1.0 library whereas I may have 2.0), similar to other issues.

So I wrote the small app below.

static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Console.WriteLine(Utility.GetVersion());

            var ads = new AppDomainSetup();
            string appBase = @"../../ExtensionLib/ExtensionLib/bin/Debug";
            ads.ApplicationBase = appBase;
            //ads.PrivateBinPath = appBase;
            //ads.ConfigurationFile = "ExtensionLib.dll.config";
            //ads.PrivateBinPathProbe = ".";
            var ad = AppDomain.CreateDomain("Extension App", null, ads);
//          var ah = new AssemblyHelper();
//            ad.AssemblyResolve += ah.MyResolveEventHandler;
//            ad.AssemblyLoad += ah.AssemblyLoadedHandler;

            //MessageBox.Show(ad.BaseDirectory);
            Assembly a = ad.Load("ExtensionLib");
            ILib l = (ILib) a.CreateInstance("LibImpl");
            l.DoSomething();

            Console.WriteLine(Utility.GetVersion());
        }
    }



Common.dll contains the Utility class, but we have different versions of that class. Both the plugin and the host application use the same ILib (defined on the same dll).

Host Application Setup

c:\....\123
   Common.dll (v 2.0)
   IntegInterface.dll (where ILib is defined, v1.0)
   LoadCommon.exe (the host)



Plugin Application Setup

c:\....\456
   Common.dll (v 1.0)
   IntegInterface.dll (where ILib is defined, v1.0)
   ExtensionLib.dll (the plugin)



When the app runs, I get an exception at the moment of ad.Load()

System.IO.FileNotFoundException was unhandled
  Message="Could not load file or assembly ''ExtensionLib'' or one of its dependencies. The system cannot find the file specified."
  Source="mscorlib"
  FileName="ExtensionLib"
  FusionLog="Assembly manager loaded from:  C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\mscorwks.dll
  Running under executable  C:\\Users\\Roberto\\Documents\\Visual Studio 2008\\Projects\\LoadCommon\\LoadCommon\\bin\\Debug\\LoadCommon.vshost.exe
  --- A detailed error log follows. \n
  === Pre-bind state information ===
  LOG: User = Roberto-PC\\Roberto
  LOG: DisplayName = ExtensionLib\n (Partial)
  LOG: Appbase = file:///C:/Users/Roberto/Documents/Visual Studio 2008/Projects/LoadCommon/LoadCommon/ExtensionLib/ExtensionLib/bin/Debug
  LOG: Initial PrivatePath = NULL
  Calling assembly : (Unknown).
  ===
  LOG: This bind starts in default load context.
  LOG: Using application configuration file: C:\\Users\\Roberto\\Documents\\Visual Studio 2008\\Projects\\LoadCommon\\LoadCommon\\ExtensionLib\\ExtensionLib\\bin\\Debug\\ExtensionLib.dll.config
  LOG: Using machine configuration file from C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\config\\machine.config.
  LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
  "
  StackTrace:
       at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
       at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
       at System.AppDomain.Load(String assemblyString)
       at System.AppDomain.Load(String assemblyString)
       at LoadCommon.Program.Main() in C:\Users\Roberto\Documents\Visual Studio 2008\Projects\LoadCommon\LoadCommon\Program.cs:line 36
       at System.AppDomain._nExecuteAssembly(Assembly 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)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 



I also tried to setup an the assemblyresolve delegate to see if I could help, no luck however, I ended up with Serialization errors even though I did tag AssemblyHelper as serializable.

At some point I will also have the IntegInterface have different versions, and am sure I will end up with a whole slew of issues.

Can someone shed some light here? Very much appreciated.

Thanks

解决方案

This is the usual confusion about loading assembly. Do you want to load Assembly by the file name of its main executable module?

Use System.Reflection.Assembly.LoadFrom(string fileName). See all other System.Reflection.Assembly.Load... methods and help pages on their differences. This call should be done in the newly created Application Domain context, not in your default (initial) Application Domain of your process. If my assumption about your plug-in assembly was wrong, please free to correct me, I''ll give you a bit different approach.

System.AppDomain ad = AppDomain.CreateDomain("Extension App", null, ads);
ad.DoCallBack(() => {
   //...
   System.Reflection.Assembly.LoadFrom(myPluginFileName);
   //...
});



If your plug-in Assembly has an entry point (EXE file) you can use System.AppDomain.ExecuteAssembly. I doubt you design you plug-ins this way (you mentioned ILib interface; if this is the interface supported by your plug-in — congratulations! This is the best approach. See be reference below on using a special assembly attribute to select a class implementing plug-in interface &mdas; very good for robustness and performance).
So, even though I don''t think your design is not bases on EXE entry point, let me show this just in case:

System.AppDomain ad = AppDomain.CreateDomain("Extension App", null, ads);
ad.ExecuteAssembly(myExeFileName);



This is great that you understand importance of loading plug-ins dynamically in the separate Application Domain, but this is only needed if you want to unload them later. In you need to load all plug-ins only once, work in one domain, your default one, do not create an extra Application Domain.

You can real all my Answers about plug-in Assemblies and using Application Domain, a variety of designs:
Create WPF Application that uses Reloadable Plugins...[^]
See also:
code generating using CodeDom[^].
Important example of use with CodeDOM compiler for use in .NET calculator:
Create WPF Application that uses Reloadable Plugins...[^].

—SA


Try to load the assembly with the version, culture and PublicKeyToken

Assembly.Load
            ("SampleAssembly, Version=2.0.0000.0, Culture=neutral, PublicKeyToken=12312320f8da049e3");


All I needed to do was make a call, so although SAK''s solution makes sense (thanks!), I decided to just use

ILib l = (ILib)ad.CreateInstanceAndUnwrap("ExtensionLib", "ExtensionLib.LibImpl");


which does the trick just fine. Furthermore, I can change the interface on the different domains and they are still somehow compatible. The transparent proxy does some funky dancing i''m sure.

Thanks all!


这篇关于AppDomain拒绝加载程序集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆