程序集加载版本不匹配:为什么它正在加载



我有两个程序集:HelloWorld.exe和Hello.dll。exe是主程序集,dll正在被主程序集使用。

我编译了HelloWorld.exe(1.0.0)和Hello.dll(1.0.0)。我把程序集放在另一个文件夹。

然后我将Hello.dll的版本更改为2.0.0,并继续用2.0.0版本覆盖Hello.dll 1.0.0。然后我启动HelloWorld.exe,它工作正常。

我预计它会立即崩溃和刻录,因为当我编译EXE时引用的Hello.dll是1.0.0。现在,1.0.0 DLL已被2.0.0取代,但它仍然工作!

根据MSDN:

默认情况下,程序集将只使用完全相同的类型用于构建和测试程序集的程序集(名称和版本号)。也就是说,如果您的程序集使用版本1.0.0.2中的类型对于另一个程序集,它将(默认情况下)不使用来自的相同类型另一个程序集的1.0.0.4版本。这种同时使用名字和版本来识别引用的程序集有助于避免"DLL地狱"升级到一个应用程序会影响其他应用程序的问题。

问题:

  1. 为什么它有效?
  2. 如何使其不工作?
  3. 附加问题:在构建过程中会发生什么?外部依赖的版本不是硬编码到主依赖吗?

注意Hello.dll不是强命名的

下面是HelloWorld.exe的清单:

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .zV.4..
  .ver 2:0:0:0
}
.assembly extern Hello
{
  .ver 2:0:0:0
}
.assembly HelloWorld
{
...//snipped
}

这是从Fuslogvw.exe(程序集绑定日志查看器)获取的程序集绑定日志:

=== Pre-bind state information ===
LOG: User = ian.uy
LOG: DisplayName = Hello, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Users/ian.uy/Desktop/HelloWorld/HelloWorld/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : HelloWorld, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:WindowsMicrosoft.NETFrameworkv2.0.50727configmachine.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:/Users/ian.uy/Desktop/HelloWorld/HelloWorld/bin/Debug/Hello.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:Usersian.uyDesktopHelloWorldHelloWorldbinDebugHello.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Hello, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
LOG: Binding succeeds. Returns assembly from C:Usersian.uyDesktopHelloWorldHelloWorldbinDebugHello.dll.
LOG: Assembly is loaded in default load context.

我遇到过同样的事情,并试图查看msbuild日志:

msbuild /v:detailed /t:build

下面几行看起来很有趣:

统一依赖"Newtonsoft。Json,版本=8.0.0.0,文化=中性,都30 ad4fe6b2a6aeed"。在"C:srcBindingTestLib1binDebugLib1.dll"中使用此版本代替原始版本"7.0.0.0",因为AutoUnify是"真正的"。

另外,如果你在构建后检查生成的app.config文件,你可能会在那里看到app.config最初没有的自动绑定重定向。

所以我们观察到的行为与"自动组装统一"one_answers"自动绑定重定向"msbuild过程有关。

以下是文档中关于AutoUnify参数的说明:

当为true时,生成的依赖关系图被自动视为如果有app的话。传入到AppConfigFile的配置文件参数。这个虚拟的App.Config文件有一个bindingRedirect条目对于每个冲突的程序集,使最高版本选择装配。这样做的后果是,永远不会有关于冲突程序集的警告,因为每个冲突都会

当为true时,每个不同的重新映射将导致高优先级注释显示旧版本和新版本,AutoUnify是真实的。

最后,如果你想观察"失败",你可以用以下参数调用msbuild:

msbuild /v:d /t:build /p:AutoUnifyAssemblyReferences=false;AutoGenerateBindingRedirects=false

为什么它工作?

因为你已经指定了;)

如何使它不工作?

  1. 右键单击解决方案资源管理器
  2. 中的DLL
  3. 选择属性
  4. 选择使用特定版本
附加问题:在构建过程中会发生什么?外部依赖的版本不是硬编码到主依赖吗?

除非您指定,否则不能。默认是关闭的。设计良好的程序集应该是向后兼容的,版本并不重要。

为了版本控制的目的,运行库区分常规程序集和强命名程序集。版本检查只对强命名程序集进行。

(来源:https://learn.microsoft.com/en-us/dotnet/framework/app-domains/assembly-versioning)

因此,答案如下:

为什么它工作?

因为程序集不是强命名的

如何使它不工作?

使程序集强命名为

在构建过程中发生了什么?

取决于
  • Use specific version = false:编译与项目中引用匹配的第一个文件,接受任何版本
  • Use specific version = true:编译第一个匹配参考的文件,包括项目
  • 中指定的版本

外部依赖的版本不是硬编码到主依赖吗?

是的,引用的程序集的版本是硬编码的。您可以通过使用反编译器(例如ILSpy)来读取这些信息

来验证这一点。

相关内容

最新更新