【问题标题】:.NET assemblyBinding configuration ignored in machine.configmachine.config 中忽略了 .NET 程序集绑定配置
【发布时间】:2008-10-13 19:05:15
【问题描述】:

我有一种情况,我需要能够根据其部分名称在 GAC 中加载程序集。为此,我在 app.config 文件中添加了以下内容:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <qualifyAssembly partialName="MyAssembly"
                     fullName= "MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcdef"/>
  </assemblyBinding>
</runtime>

这正是我想要的方式。但是,如果我在 machine.config 文件中放置相同的元素,它似乎会被忽略,并且在尝试加载 MyAssembly 时出现 FileNotFoundExceptions。

以下是元素在我的app.config中时的程序集绑定日志,并且绑定成功:

LOG:此绑定在默认加载上下文中开始。
LOG:使用应用程序配置文件:C:\Documents and Settings\jon_scheiding\My Documents\Source\Testing\Test Projects 1\Cmd\bin\Debug\Testers.Cmd.vshost.exe.config
LOG:使用 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config 中的机器配置文件。
LOG:部分引用来自配置文件。新参考:MyAssembly,Version=1.0.0.0,Culture=neutral,PublicKeyToken=0123456789abcdef。
日志:政策后参考:MyAssembly,Version=1.0.0.0,Culture=neutral,PublicKeyToken=0123456789abcdef
日志:通过查看 GAC 找到程序集。
LOG:绑定成功。从 C:\WINDOWS\assembly\GAC_MSIL\MyAssembly\1.0.0.0__b20f4683c1030dbd\MyAssembly.dll 返回程序集。
LOG:程序集在默认加载上下文中加载。

与我的配置在 machine.config 中时的日志对比,并且绑定失败:

LOG:此绑定在默认加载上下文中开始。
LOG:使用应用程序配置文件:C:\Documents and Settings\jon_scheiding\My Documents\Source\Testing\Test Projects 1\Cmd\bin\Debug\Testers.Cmd.vshost.exe.config
LOG:使用 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config 中的机器配置文件。
LOG:此时未将策略应用于引用(私有、自定义、部分或基于位置的程序集绑定)。
日志:尝试下载新的 URL 文件:///C:/Documents and Settings/jon_scheiding/My Documents/Source/Testing/Test Projects 1/Cmd/bin/Debug/MyAssembly.DLL。
日志:尝试下载新的 URL 文件:///C:/Documents and Settings/jon_scheiding/My Documents/Source/Testing/Test Projects 1/Cmd/bin/Debug/MyAssembly/MyAssembly.DLL。
日志:正在尝试下载新的 URL 文件:///C:/Documents and Settings/jon_scheiding/My Documents/Source/Testing/Test Projects 1/Cmd/bin/Debug/MyAssembly.EXE。
日志:尝试下载新的 URL 文件:///C:/Documents and Settings/jon_scheiding/My Documents/Source/Testing/Test Projects 1/Cmd/bin/Debug/MyAssembly/MyAssembly.EXE。
LOG:所有探测 URL 都已尝试并失败。

问题似乎出在第四行,“Policy not being applied to reference at this time”。但是,关于此消息的含义或解决方法,我几乎找不到文档。

如何让框架识别我的 元素?

提前致谢!

【问题讨论】:

    标签: .net configuration clr gac fusion


    【解决方案1】:

    框架不会从 machine.config 中读取qualifyAssebmly 配置,它只会从您的应用程序配置文件中读取它。

    框架可以识别您的 runtim 元素,但是它不能识别qualifyAssembly 元素。

    【讨论】:

      【解决方案2】:

      我很晚才回到这个需求,因为我们在 GAC 中有一些程序集,而像 NHibernate 之类的东西需要解决它们。无需将所有这些qualifyAssembly 元素添加到每个app.config,下面的代码允许我们将它们添加到我们的machine.config。

      using System;
      using System.Collections.Generic;
      using System.Configuration;
      using System.IO;
      using System.Reflection;
      using System.Xml;
      using System.Xml.XPath;
      
      namespace MyNamespace {
      
          /// <summary>
          /// Implements <see cref="IDisposable"/> to provide a scope for resolving
          /// assemblies described in the machine.config file with 
          /// &lt;qualifyAssembly&gt; elements.
          /// </summary>
          /// <remarks>
          /// Because the framework only respects &lt;qualifyAssembly&gt; at the
          /// application configuration level, this class provides similar
          /// functionality for this element at the machine configuration level.
          /// You can wrap a new instance of this class in a <b>using</b> statement
          /// to get resolution within a specific scope; or, you can call the 
          /// <see cref="AssemblyResolver.Attach()"/> method to get 
          /// resolution for the lifetime of the current <see cref="AppDomain"/>.
          /// </remarks>
          public sealed class AssemblyResolver : IDisposable {
      
              #region Private fields and implementation
      
              private static Dictionary<string, string> _qualifiedNames;
      
              private static Assembly ResolveAssembly(object sender, ResolveEventArgs args) {
                  if(_qualifiedNames == null) {
                      //
                      // Lazily initialize short/long name mappings.
                      //
                      _qualifiedNames = BuildQualifiedNameList();
                  }
      
                  if(!_qualifiedNames.ContainsKey(args.Name)) {
                      return null;
                  }
      
                  try {
                      return Assembly.Load(_qualifiedNames[args.Name]);
                  }
                  catch(FileNotFoundException) {
                      //
                      // TODO: Should this exception be propogated?
                      // It probably should not be hidden from the consumer
                      // since it likely indicates a configuration error.
                      //
                      return null;
                  }
              }
      
              private static Dictionary<string, string> BuildQualifiedNameList() {
                  var dict = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
      
                  //
                  // Get runtime XML data
                  //
                  var xml = GetConfigXml(GetMachineRuntimeSection());
                  if(xml == null) {
                      return dict;
                  }
      
                  //
                  // Iterate the qualifyAssembly elements and register in the list
                  //
                  var navigator = xml.CreateNavigator();
                  foreach(XPathNavigator qualifyAssembly in navigator.Select("runtime/asm:assemblyBinding/asm:qualifyAssembly", CreateNamespaceManager())) {
                      dict.Add(
                          qualifyAssembly.GetAttribute("partialName", string.Empty),
                          qualifyAssembly.GetAttribute("fullName", string.Empty));
                  }
      
                  return dict;
              }
      
              private static ConfigurationSection GetMachineRuntimeSection() {
                  System.Configuration.Configuration machineConfig = ConfigurationManager.OpenMachineConfiguration();
                  return machineConfig.GetSection("runtime") as ConfigurationSection;
              }
      
              private static IXPathNavigable GetConfigXml(ConfigurationSection runtimeSection) {
                  var ignoreSection = runtimeSection as IgnoreSection;
                  if(ignoreSection == null) {
                      return null;
                  }
      
                  //
                  // Cheat via Reflection to get the XML content of the config
                  // section.
                  //
                  FieldInfo field = typeof(IgnoreSection).GetField("_rawXml", BindingFlags.Instance | BindingFlags.NonPublic);
                  string rawXml = (string)field.GetValue(ignoreSection);
                  return new XPathDocument(new StringReader(rawXml));
              }
              private static IXmlNamespaceResolver CreateNamespaceManager() {
                  var nsmgr = new XmlNamespaceManager(new NameTable());
                  nsmgr.AddNamespace("asm", "urn:schemas-microsoft-com:asm.v1");
                  return nsmgr;
              }
      
              #endregion
      
              /// <summary>
              /// Creates a new <see cref="AssemblyResolver"/>.
              /// </summary>
              public AssemblyResolver() {
                  AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
              }
      
              /// <summary>
              /// Removes the current <see cref="AssemblyResolver"/>
              /// from the <see cref="AppDomain"/>.
              /// </summary>
              public void Dispose() {
                  AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(ResolveAssembly);
                  GC.SuppressFinalize(this);
              }
      
              /// <summary>
              /// Provides qualified assembly resolution for the lifetime of the
              /// current <see cref="AppDomain"/>.
              /// </summary>
              public static void Attach() {
                  Attach(AppDomain.CurrentDomain);
              }
      
              /// <summary>
              /// Provides qualified assembly resolution for the lifetime of an
              /// <see cref="AppDomain"/>.
              /// </summary>
              /// <param name="appDomain">
              /// The <see cref="AppDomain"/> to service.
              /// </param>
              public static void Attach(AppDomain appDomain) {
                  appDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
              }
      
          }
      }
      

      在大多数情况下,我们通过这样使用它来限制它的范围:

      using(new AssemblyResolver()) {
          //
          // NHibernate initialization or whatever
          //
      }
      

      它也可以用在应用程序启动代码或 global.asax 中,并在应用程序的生命周期内持续存在,如下所示:

      AssemblyResolver.Attach();
      //
      // or
      //
      AssemblyResolver.Attach(AppDomain.CurrentDomain);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-05
        • 1970-01-01
        • 2010-10-12
        • 2023-03-29
        相关资源
        最近更新 更多