自从MS14-059以来,System.Web.MVC未被复制到bin文件夹中。如何防止由于Windows更新导致创建缺少DLL的构建?

36
今天早上有报道说我们QA服务器上的Web应用程序完全崩溃了,从Web.config中报告了以下错误:
“无法加载文件或程序集'System.Web.Mvc,Version=5.1.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35'或其某个依赖项。系统找不到指定的文件。”
记得看到一个Windows更新提到MVC,我进行了一些挖掘,并发现有很多人报告最近的Windows更新破坏了MVC。
经过对这些问题和我们的服务器的深入挖掘,似乎咬我们的东西与其他问题中的不符,但它似乎与之相关。以下是我们认为我们所知道的:
我们的应用程序使用ASP.NET MVC 5.1,该应用程序已损坏。
MVC是通过NuGet安装的。
我们的BuildServer和QA服务器没有安装MVC 5.1(因此未GAC'd)。
我们相信已经破坏了导致创建“坏构建”的原因:
通过Windows Update在BuildServer上安装了MVC 5.1的补丁,尽管在GAC中没有安装MVC 5.1。
该补丁已将MVC 5.1的“更新”版本放入GAC中。
当DLL位于GAC中时,CopyLocal=true被忽略;因此,自从打补丁以来,这意味着来自BuildServer的应用程序构建不再具有输出文件夹中的System.Web.MVC。 由于我们的QA服务器上没有在GAC中安装System.Web.MVC(它们尚未被修补),因此应用程序现在失败,因为找不到System.Web.MVC。
假设上述行为是正确的,这意味着任何时候当微软通过Windows Update服务提供NuGet DLL(我们没有在GAC中的),我们的BuildServer将开始生成不完整的构建(缺少那些已被注入到GAC中的DLL)。升级到MVC 5.2解决了这个问题(可能是因为它没有被修补程序所覆盖,因此没有被注入到GAC中);该DLL现在被复制到输出文件夹。升级到5.2.2的差异中没有任何更改,除了版本号的变化(特别是没有添加/编辑节点)。我们不希望开始GAC所有东西,也不希望创建手动构建步骤来复制我们所有的DLL到bin文件夹中,以防万一微软修补它们。那么,今天我们可以改变什么来确保我们永远不会在未来出现BuildServer默默地生成错误的构建?

2
.NET版本控制如此混乱令人惊讶。 - usr
3
如果默认设置为true,则项目文件中缺少“复制本地”设置,将其设置为false然后再设置为true即可添加该设置。参见:http://blogs.msdn.com/b/jjameson/archive/2009/11/18/the-copy-local-bug-in-visual-studio.aspx - Guffa
1
@Guffa 这并没有解释为什么我们升级到MVC 5.2.2后问题得到了解决。除了版本号的更改之外,它并没有引入任何项目变更。 - Danny Tuppeny
@Guffa 在MVC v5项目中没有(缺少5.1的DLL,但包括了5.2的,尽管在项目文件中没有更改异常版本号 :/)。 - Danny Tuppeny
如果您能启用绑定融合日志并查看加载工作的详细信息,那将非常有帮助。 - vcsjones
显示剩余3条评论
3个回答

14
一个 MVC 5.1 的补丁已经通过 Windows Update 安装在 BuildServer 上,尽管 GAC 中没有安装 MVC 5.1。
是的,实际上这种行为是按设计来的。请参考 http://blogs.msdn.com/b/dotnet/archive/2014/01/22/net-4-5-1-supports-microsoft-security-updates-for-net-nuget-libraries.aspx
补丁已将"MVC 5.1更新"版本放置于GAC中。
是的,没错;这是补丁运行更新代码而非旧代码的方式。请参见https://technet.microsoft.com/en-us/library/security/ms14-059
当DLL位于GAC中时,CopyLocal=true会被忽略;因此,自从打了补丁以后,这意味着我们从BuildServer构建的应用程序不再在输出文件夹中具有System.Web.MVC。
事实并非如此。实际上发生的是,之前设置为CopyLocal=true的项目被切换为CopyLocal=false。可以通过以下两种方式之一设置CopyLocal:1)如果.csproj文件中有显式的<Private>True</Private>设置;或者2)默认情况下,如果没有这样的设置(GAC的程序集默认情况下不会CopyLocal;其他程序集则会CopyLocal)。
因此,在这种情况下似乎发生的是,您的项目文件中没有这个设置。因此,在补丁安装之前,GUI基于评估的默认值显示设置(CopyLocal=true),但是在安装补丁之后,GUI现在将显示GAC'd程序集的新默认值(CopyLocal=false)。
“由于我们QA服务器上的GAC中没有System.Web.MVC(它们尚未被修补),因此应用程序现在失败了,因为找不到System.Web.MVC。”
“没错。”
假设上述行为是正确的,这意味着每当微软通过Windows Update服务提供一个NuGet DLL,而我们没有它在GAC中时,我们的BuildServer将开始生成不完整的构建(缺少那些已注入到GAC中的DLL)。对于任何.csproj引用,如果没有显式的True设置,则是正确的。此外,请注意,使用NuGet更新您的MVC引用可能会删除即使以前存在也是如此的设置。请参见http://nuget.codeplex.com/workitem/4344
升级到MVC 5.2可解决此问题(可能是因为它没有被修补,因此没有注入到GAC中); DLL现在已复制到输出文件夹。 升级到5.2.2的差异中没有任何更改,除了版本号更改(特别没有添加/编辑节点)。
那是正确的。由于MVC 5.2没有GAC'd,即使没有显式的True设置,非GAC'd程序集的默认值也将是CopyLocal=true。
我们不希望对所有东西都进行GAC,也不想创建手动构建步骤来将所有DLL复制到bin文件夹中,以防万一微软修补它们。那么,今天我们能做些什么来确保我们的BuildServer在未来MS修补其他DLL时不会默默地生成错误的构建版本呢?
您今天可以做的最好的事情是:
1. 在您的.csproj文件中为所有NuGet包装配件引用设置明确的<Private>True</Private>设置。 2. 在NuGet修复了问题#4344之前,每次使用NuGet更新包引用时,请返回到您的.csproj文件并重新添加明确的<Private>True</Private>设置。

5
我相信此问题在.Net Web开发工具和UI博客中得到了解决:链接 我不会在这里重复整个问题,因为该链接已经很好地解释了问题和解决方案。
然而,为了重申关键点,这应该能够解释为什么会发生这种情况:
  • 在补丁KB2994397中添加了MVC 5.1到GAC。

  • 似乎有一个NuGet错误会重置CopyLocal标志。(见此链接) 这意味着当使用上述补丁的机器部署到未安装补丁的机器时,它将中断!

  • MVC 4的程序集版本号也被同一安全更新 - MS14-059递增(因此不会使用GAC版本)这解释了为什么MVC 4版本仍然可用 - 尽管它在GAC中。


我并不完全理解最后一部分;即使 GAC 中的 v4 DLL 版本号不同,如果它更高,那么它仍然会从 GAC 中使用吗? - Danny Tuppeny
1
尽管这回答了很多问题,但它并没有回答主要问题,即我们如何在未来保护自己免受此类事件的影响?目前似乎来自微软的任何补丁都会导致我们的构建服务器悄无声息地创建错误的构建。 - Danny Tuppeny
针对您的第一个评论:应该是更新只被应用到了构建服务器上。 因此,在您的项目中,它们仍然会引用旧的MVC 4程序集版本(不再是构建服务器GAC中的版本),因此仍然会复制旧版本。当Nuget在您的项目中下一次更新MVC4时,如果未设置copyLocal,则预计MVC4将会出现故障。目前不确定最好的防止出现故障的方法 - 大概就是确保永远不会取消设置CopyLocal! - James S

-2

我在我的博客中添加了有关此问题的注释: Microsoft Asp.Net MVC安全更新MS14-059破坏了我的构建!

您对问题的分析非常准确,当程序集位于GAC中时,默认情况下将复制本地标志设置为false,手动将其设置为true应该可以解决此问题。

升级到5.2.2甚至更好,除了安全修复外,还可以获得新版本的优点。


这并没有回答关于为什么4没有受到影响,5.1受到了影响,而5.2似乎没有受到影响的问题;也没有解释如果每次升级时CopyLocal标志被NuGet重置时如何防止将来发生此类情况。 - Danny Tuppeny
@Miguel,请问你能提供“Visual Studio 2010的MVC 3.0.1工具刷新”的下载链接吗?我昨天已经搜索了很多次,但没有找到。 - ken2k
MVC 3.1 工具更新:http://www.microsoft.com/en-us/download/details.aspx?id=1491 请注意,如果您的计算机上安装了 NuGet 1.2 或 1.3 版本,则需要在安装 MVC 3.1 工具更新之前将其卸载,然后再安装最新版本的 NuGet,因为这会导致已知问题。 - Miguel Lacouture

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接