如果 msbuild 的版本低于项目依赖项之一的要求,则 msbuild 拒绝复制未签名的 dll - 这是设计使然吗?
msbuild refuses to copy unsigned dll if it is of lower version than demanded by one of the project dependencies - is it by design?
我有以下情况:
- 所有涉及的dll都是未签名的
- 解决方案中的所有项目都依赖于 Shared.dll
的 1.0.21221.1 版本
- 解决方案中部分项目的部分NuGet依赖依赖同一个dll的1.0.21237.1版本
- 构建 Web 应用程序时(让我们将其命名为 Api),预计会将 Shared.dll 从
$(OutDir)
复制到$(OutDir)_PublishedWebsites\Api\bin
文件夹。在 $(OutDir)
中找到的 Shared.dll 的版本为 1.0.21221.1.
- 未复制 Shared.dll,Web 应用程序无法 运行。
这是二进制日志的证据:
图表 A - 版本冲突:
图表 B - ResolveAssemblyReference 指示不要复制 Shared.dll:
我知道 msbuild 不喜欢版本冲突的想法,但不复制 dll 会产生彻头彻尾的错误,因为应用程序无法启动。
我知道可以通过添加程序集绑定重定向来解决它。但是我认为对于未签名的程序集来说是不必要的。我是理解错了还是漏掉了什么?
编辑 1
以下是我对评论中提出的问题的回答:
(不幸的是我被要求混淆一些关键字,我不知道为什么)
- Api项目引用Shared.dll到底是怎么回事?
正如我们在 图表 B 中看到的那样 Shared.dll 是 Api 的传递依赖。事实上,Api 依赖于 Xyz.BusinessApi 是这样的:
<Reference Include="Xyz.BusinessAPI" />
现在 DLL 通过相应的 NuGet 依赖项依赖于 Shared.dll,这里是 Xyz.BusinessAPI 的 project.assets.json 文件的片段:
- 还有哪些其他项目参考 Shared.dll 以及如何参考?
有很多项目将其作为版本 1.0.21221.1 的 NuGet 包引用。问题是一些项目还引用了另外两个 NuGet 包,而这两个 NuGet 包又依赖于同一个 NuGet 包的版本 1.0.21237.1。这在 RAR 输出中指示 - 请参阅 图表 A。
我想强调 - 没有项目引用 Shared.dll 作为原始 dll,仅作为 NuGet 包或通过其他 NuGet 或项目或 项目 dll 间接引用。 Project dll 是来自先前构建的解决方案的项目的 dll - 我们不允许项目引用其他解决方案,因此如果项目是在先前的解决方案中构建的,那么它将在后续解决方案中作为 DLL 被引用。
- 从OutDir复制到_PublishedWebsites\api\bin的机制是什么?
这是来自 C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\WebApplications\Microsoft.WebApplication.targets 的标准 Web 应用程序发布目标 _CopyFilesMarkedCopyLocal
:
<!-- copy any referenced assemblies to _PublishedWebsites\app\bin folder -->
<Copy SourceFiles="@(ReferenceCopyLocalPaths)"
DestinationFiles="@(ReferenceCopyLocalPaths->'$(WebProjectOutputDir)\bin\%(DestinationSubDirectory)%(Filename)%(Extension)')"
SkipUnchangedFiles="true"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"/>
- Shared.dll 是如何进入 OutDir 的?
我们所有的代码都内置在共享 bin 目录中 - 我们将 OutDir
设置为所有项目的相同值。因此,所有项目二进制文件及其依赖项,包括 Shared.dll 首先在那里结束。
- binlog是否有双写?
是的,但我认为它们不相关:
简短的回答是您的项目间接依赖于 Shared.dll 的两个版本:1.0.21221.1
和 1.0.21237.1
。
RAR(MSBuild ResolveAssemblyReference 任务)检查了所有 .dll 的所有引用并找到了这两个版本。它报告了冲突:
注意Shared.dll21221在方括号中报告找到的文件路径,21237报告[](表示没有找到该版本的文件)。
使用 There was a conflict under($rar)
或 $warning under($rar)
搜索这些内容很有用。
现在,OutDir 只包含 Shared.dll 21221,因此无法在任何地方找到版本为 21237 的 Shared.dll。
诀窍是搜索 Shared.dll under($rar project(api.csproj))
您会从 RAR 中找到相关消息:
Considered "C:\Xyz\bin.link\Shared.dll",
but its name "Shared, Version=1.0.21221.1, Culture=neutral, PublicKeyToken=null"
didn't match the expected name "Shared, Version=1.0.21237.1, Culture=neutral, PublicKeyToken=null".
所以,它看到了冲突,决定统一到更高版本(21237),但没有找到那个版本的文件。所以 21221 的引用不是 CopyLocal,因为它没有在那个版本上统一,而对 21237 的引用没有被解析,因为找不到那个版本的文件。
要解决此问题,我建议添加对版本 21237 的 Shared.dll 的显式引用(通过 NuGet 或通过包引用上的 GeneratePathProperty
元数据:https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#generatepathproperty)。如果您使用 GeneratePathProperty,则可以使用 $(PkgFoo_Bar)\lib\net472\Shared.dll
或类似方法直接引用 .dll。还要添加从 21221 到 21237 的绑定重定向以解决冲突。一旦正确的版本 (21237) 出现在您的 OutDir 中,它将被正确复制到输出。
希望这能说明问题。
我有以下情况:
- 所有涉及的dll都是未签名的
- 解决方案中的所有项目都依赖于 Shared.dll 的 1.0.21221.1 版本
- 解决方案中部分项目的部分NuGet依赖依赖同一个dll的1.0.21237.1版本
- 构建 Web 应用程序时(让我们将其命名为 Api),预计会将 Shared.dll 从
$(OutDir)
复制到$(OutDir)_PublishedWebsites\Api\bin
文件夹。在$(OutDir)
中找到的 Shared.dll 的版本为 1.0.21221.1. - 未复制 Shared.dll,Web 应用程序无法 运行。
这是二进制日志的证据:
图表 A - 版本冲突:
图表 B - ResolveAssemblyReference 指示不要复制 Shared.dll:
我知道 msbuild 不喜欢版本冲突的想法,但不复制 dll 会产生彻头彻尾的错误,因为应用程序无法启动。
我知道可以通过添加程序集绑定重定向来解决它。但是我认为对于未签名的程序集来说是不必要的。我是理解错了还是漏掉了什么?
编辑 1
以下是我对评论中提出的问题的回答:
(不幸的是我被要求混淆一些关键字,我不知道为什么)
- Api项目引用Shared.dll到底是怎么回事?
正如我们在 图表 B 中看到的那样 Shared.dll 是 Api 的传递依赖。事实上,Api 依赖于 Xyz.BusinessApi 是这样的:
<Reference Include="Xyz.BusinessAPI" />
现在 DLL 通过相应的 NuGet 依赖项依赖于 Shared.dll,这里是 Xyz.BusinessAPI 的 project.assets.json 文件的片段:
- 还有哪些其他项目参考 Shared.dll 以及如何参考?
有很多项目将其作为版本 1.0.21221.1 的 NuGet 包引用。问题是一些项目还引用了另外两个 NuGet 包,而这两个 NuGet 包又依赖于同一个 NuGet 包的版本 1.0.21237.1。这在 RAR 输出中指示 - 请参阅 图表 A。
我想强调 - 没有项目引用 Shared.dll 作为原始 dll,仅作为 NuGet 包或通过其他 NuGet 或项目或 项目 dll 间接引用。 Project dll 是来自先前构建的解决方案的项目的 dll - 我们不允许项目引用其他解决方案,因此如果项目是在先前的解决方案中构建的,那么它将在后续解决方案中作为 DLL 被引用。
- 从OutDir复制到_PublishedWebsites\api\bin的机制是什么?
这是来自 C:\Program Files (x86)\Microsoft Visual Studio19\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\WebApplications\Microsoft.WebApplication.targets 的标准 Web 应用程序发布目标 _CopyFilesMarkedCopyLocal
:
<!-- copy any referenced assemblies to _PublishedWebsites\app\bin folder -->
<Copy SourceFiles="@(ReferenceCopyLocalPaths)"
DestinationFiles="@(ReferenceCopyLocalPaths->'$(WebProjectOutputDir)\bin\%(DestinationSubDirectory)%(Filename)%(Extension)')"
SkipUnchangedFiles="true"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"/>
- Shared.dll 是如何进入 OutDir 的?
我们所有的代码都内置在共享 bin 目录中 - 我们将 OutDir
设置为所有项目的相同值。因此,所有项目二进制文件及其依赖项,包括 Shared.dll 首先在那里结束。
- binlog是否有双写?
是的,但我认为它们不相关:
简短的回答是您的项目间接依赖于 Shared.dll 的两个版本:1.0.21221.1
和 1.0.21237.1
。
RAR(MSBuild ResolveAssemblyReference 任务)检查了所有 .dll 的所有引用并找到了这两个版本。它报告了冲突:
注意Shared.dll21221在方括号中报告找到的文件路径,21237报告[](表示没有找到该版本的文件)。
使用 There was a conflict under($rar)
或 $warning under($rar)
搜索这些内容很有用。
现在,OutDir 只包含 Shared.dll 21221,因此无法在任何地方找到版本为 21237 的 Shared.dll。
诀窍是搜索 Shared.dll under($rar project(api.csproj))
您会从 RAR 中找到相关消息:
Considered "C:\Xyz\bin.link\Shared.dll",
but its name "Shared, Version=1.0.21221.1, Culture=neutral, PublicKeyToken=null"
didn't match the expected name "Shared, Version=1.0.21237.1, Culture=neutral, PublicKeyToken=null".
所以,它看到了冲突,决定统一到更高版本(21237),但没有找到那个版本的文件。所以 21221 的引用不是 CopyLocal,因为它没有在那个版本上统一,而对 21237 的引用没有被解析,因为找不到那个版本的文件。
要解决此问题,我建议添加对版本 21237 的 Shared.dll 的显式引用(通过 NuGet 或通过包引用上的 GeneratePathProperty
元数据:https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#generatepathproperty)。如果您使用 GeneratePathProperty,则可以使用 $(PkgFoo_Bar)\lib\net472\Shared.dll
或类似方法直接引用 .dll。还要添加从 21221 到 21237 的绑定重定向以解决冲突。一旦正确的版本 (21237) 出现在您的 OutDir 中,它将被正确复制到输出。
希望这能说明问题。