【问题标题】:How do I manually edit the manifest of my Visual Studio project to explicitly specify referenced assemblies?如何手动编辑 Visual Studio 项目的清单以明确指定引用的程序集?
【发布时间】:2012-08-19 01:26:10
【问题描述】:

由于对 log4net 强大的命名和版本控制感到非常头疼,即旧的 1.2.10 名称,新的 1.2.11 名称,以及(上帝帮助我)SAP 制作并推入 GAC 的 1.2.10它自己的强名称,我的应用程序将拒绝在除我自己的机器之外的任何机器上运行。它一直在寻找不存在的强命名 SAP 版本的 1.2.11 版本。

由于我的项目中没有任何东西是强命名的,我想阻止编译器寻找一个强命名的程序集,只加载我放在目录中的那个。由于它抱怨清单不匹配,我试图在我的项目中找到该版本和公钥的引用,但我做不到。这个清单似乎是在编译时创建的。

我怎样才能覆盖它?是否有一个属性或开关或条件编译可以用来准确指定我希望引用的程序集?

最终我想使用1.2.11版本的log4net,并强制程序集忽略GAC中的版本,只查看本地bin目录。这真的不应该这么痛苦。

【问题讨论】:

  • 你试过binding redirect吗?
  • 我有……好像没什么区别。
  • 你得到了 log4net 的源代码,创建你自己的 99.99 版本,这样你就不会再遇到这个问题了。
  • 我不确定这会有所帮助;我很确定这与 GAC 中强命名的 SAP log4net 程序集有关。

标签: c# visual-studio-2010 compilation dependencies manifest


【解决方案1】:

运行时指令

在运行时,您可以使用AppDomain.AssemblyResolve 来解决程序集版本控制 问题,当您不关心存在什么特定版本时,您只想加载/bin 文件夹中的内容。此代码是使用inspiration from here 创建的。

string[] ignoreAssembyVersions = new string[] { "log4net" };
AppDomain.CurrentDomain.AssemblyResolve += (_, assembly) =>
{
    //ignore the vesion number and return any version that has been loaded
    var name = new AssemblyName(assembly.Name);
    var shortName = name.Name; // retrieve short name
    if (ignoreAssembyVersions.Contains(shortName)) // compare against list of assemblies we ignore revisions for
    {
        // check if this assembly is already loaded under a different version #
        Assembly[] allAss = AppDomain.CurrentDomain.GetAssemblies();
        List<Assembly> list = new List<Assembly>(allAss);
        var loadedAssembly = list.Find(ass => new AssemblyName(ass.FullName).Name == shortName); // check if we have any version loaded yet
        if (loadedAssembly != null)
            return loadedAssembly;
        else // assembly has not yet been loaded in this domain
        {   // probe for assembly by name
            Assembly probedAssembly = Assembly.LoadFrom(string.Format("{0}.dll", shortName)); // probe for any match on assembly.dll 
            return probedAssembly;
        }
    }
    return null; // ignore binding failure -> pass up the stack
};

处理AssemblyResolve 事件的替代方法是use a custom bindingRedirect policy。但是 - 这仅在您知道 /bin 中存在什么版本或当前在应用程序域中加载时才有效。

构建时指令

如果您想控制which assembly version is used at build-time,您可以使用Specific Version='true' 来添加您添加的程序集引用。

【讨论】:

  • 我把它放到了一个 Application_Start 方法中,但它什么也没做。这种版本控制方法是否适用于强名称问题?
  • 根据您的应用程序的类型和行为,您可以将其放在多个位置。我将它放在一个静态 ctor 中,这样它只会被调用一次以供整个应用程序域(所有线程)使用。 CurrentDomain 表示给定线程的活动应用程序域 (AppDomain)。
  • 您应该调试以确保您使用适当的程序集名称正确处理事件。您应该查看应用程序域 (AppDomain.CurrentDomain.GetAssemblies()) 中加载了哪些程序集。如果强名称已经加载,那么您可能需要调整事件逻辑 - 这取决于具体情况。还要确保回收应用程序池以重新加载程序集。
  • 我不熟悉静态 ctor,您能否在回答中提供一个示例?我觉得这是正确的轨道,但我似乎仍然无法让它发挥作用。
  • 静态 ctor 的声明方式与常规 ctor 一样,只是它们的前缀为 static。见MSDN for further reference
【解决方案2】:

我希望我已经理解了您的问题。您可以考虑使用dependentAssembly 配置来支持每个程序集的自定义绑定策略和程序集位置。 这是我的配置策略的快照,用于查找另一个版本的程序集System.Data.SQLite

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Data.SQLite" publicKeyToken="db937bc2d44ff139" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.0.81.0" newVersion="1.0.81.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

【讨论】:

  • 不幸的是,我认为不仅仅是版本。我确实尝试过进行反向版本绑定映射,但无济于事。我真的很想在编译中明确强制汇编版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多