VS2013发布Web部署任务失败该文件正在使用中

我使用VS2013 Premium将站点发布到Windows Server 2012.所有文件都发布正常,除了这些:SqlServerTypes \ x64 \ msvcr100.dll

SqlServerTypes \ 64 \ SqlServerSpatial110.dll

SqlServerTypes \ 86 \ msvcr100.dll

SqlServerTypes \ 86 \ SqlServerSpatial110.dll

我为上面尝试发布的每个文件都遇到了这种错误:Web部署任务失败。 (文件’msvcr100.dll’正在使用中。有关详细信息,请访问: http : //go.microsoft.com/fwlink/?LinkId = 221672 #ERROR_FILE_IN_USE。)

有趣的是,这些文件是第一次发布(当它们不在服务器上时),然后它们不再被覆盖。 试过2个不同的Web服务器。 我在这里遵循指南: http : //blogs.msdn.com/b/webdev/archive/2013/10/30/web-publishing-updates-for-app-offline-and-usechecksum.aspx

…但它只是设法使网站脱机(VS放置app_offline.htm)但发布仍然失败并出现相同的错误。 所有其他文件发布完美。

有任何想法吗?

您可以在发布期间使应用程序脱机,希望释放文件锁定并允许您更新它。

我有一段时间在博客上写这篇文章 。 概述的支持在Azure SDK和Visual Studio Update中提供。 我不记得确切的版本,但我可以找到,如果需要。 在博客文章附近/之后的任何更新都应该没问题。

先决条件:

  • VS 2012 + VS更新/ VS 2013 + VS更新/ VS2015
  • MSDeploy v3

注意:如果要从CI服务器发布,CI服务器也需要上面的更新

编辑发布配置文件

在VS中创建Web发布配置文件时,对话框中的设置存储在Properties\PublishProfiles\作为以.pubxml结尾的文件。 注意:还有.pubxml.user文件,不应修改该文件

要在.pubxml文件.pubxml您的应用程序脱机, .pubxml添加以下属性。

true

笔记

ASP.NET必需

在MSDeploy端实现此方法的方法是将app_offline.htm文件放在网站/应用程序的根目录中。 从那里,asp.net运行时将检测到并使您的应用程序脱机。 因此,如果您的网站/应用程序没有启用asp.net,则此function将无效。

它可能无法工作的情况

这样做的实现使得应用程序在发布开始之前可能不会严格脱机。 首先删除app_offline.htm文件,然后MSDeploy将开始发布文件。 它不等待ASP.NET检测文件并实际使其脱机。 因此,您可能遇到仍然遇到文件锁的情况。 默认情况下,VS启用重试,因此通常应用程序将在其中一个重试期间脱机,一切都很好。 在某些情况下,ASP.NET可能需要更长时间才能响应。 这有点棘手。

如果你添加true并且你的应用程序没有很快下线,那么我建议你在发布开始之前使应用程序脱机。 有几种方法可以远程执行此操作,但这取决于您的设置。 如果您只有MSDeploy访问权限,则可以尝试以下顺序:

  1. 使用msdeploy.exe删除app_offline.htm以使您的站点脱机
  2. 使用msdeploy.exe发布您的应用程序(_确保同步不会删除app_offline.htm文件_)
  3. 等待一段时间
  4. 发布网站
  5. 使用msdeploy.exe通过删除app_offline.htm使应用程序联机

我在http://sedodream.com/2012/01/08/howtotakeyourwebappofflineduringpublishing.aspx上写了一篇关于如何做到这一点的博客。 该博客文章中唯一缺少的是延迟等待网站实际脱机。 您还可以创建一个直接调用msdeploy.exe的脚本,而不是将其集成到项目构建/发布过程中。

我找到了http://blogs.msdn.com/b/webdev/archive/2013/10/30/web-publishing-updates-for-app-offline-and-usechecksum.aspx上的解决方案没有找到的原因为原始海报工作,我有一个解决方法。

EnableMSDeployAppOffline方法的问题在于它只回收托管应用程序的应用程序域。 它不会回收应用程序域所在的应用程序池工作进程(w3wp.exe)。

拆除并重新创建应用程序域不会影响有问题的Sql Server Spatial dll。 这些dll是非托管代码,通过interop LoadLibray调用手动加载。 因此,dll不在app域的范围之内。

为了释放应用程序池进程对其进行的文件锁定,您需要回收应用程序池,或者手动从内存中卸载dll。

Microsoft.SqlServer.Types nuget包附带一个类,用于加载名为SqlServerTypes.Utilities的Spatial dll。 您可以修改LoadNativeAssemblies方法以在卸载应用程序域时卸载非托管dll。 通过此修改,当msdeploy复制app_offline.htm时,app域将卸载然后卸载托管dll。

 private static IntPtr _msvcrPtr = IntPtr.Zero; private static IntPtr _spatialPtr = IntPtr.Zero; public static void LoadNativeAssemblies(string rootApplicationPath) { if (_msvcrPtr != IntPtr.Zero || _spatialPtr != IntPtr.Zero) throw new Exception("LoadNativeAssemblies already called."); var nativeBinaryPath = IntPtr.Size > 4 ? Path.Combine(rootApplicationPath, @"SqlServerTypes\x64\") : Path.Combine(rootApplicationPath, @"SqlServerTypes\x86\"); _msvcrPtr = LoadNativeAssembly(nativeBinaryPath, "msvcr100.dll"); _spatialPtr = LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial110.dll"); AppDomain.CurrentDomain.DomainUnload += (sender, e) => { if (_msvcrPtr != IntPtr.Zero) { FreeLibrary(_msvcrPtr); _msvcrPtr = IntPtr.Zero; } if (_spatialPtr != IntPtr.Zero) { FreeLibrary(_spatialPtr); _spatialPtr = IntPtr.Zero; } }; } 

这种方法有一点需要注意。 它假定您的应用程序是在使用Spatial dll的工作进程中运行的唯一应用程序。 由于应用程序池可以托管多个应用程序,因此如果另一个应用程序也加载了它们,则不会释放文件锁 这将阻止您的部署使用相同的文件锁定错误。

IIS和文件锁存在已知问题(为什么它们尚未解决但我不知道)。

我想问的问题是,你是否需要重新部署这些文件?

我认识到文件名,并将它们记为系统文件,这些文件应该已经存在于服务器上,或者根本不需要重新部署。

我在IIS方面不是很有经验,但我之前遇到过这个问题,而且我的一些经验丰富的同事告诉我,这就像我说的一个已知的IIS问题,我相信你的问题的答案是:

  1. 避免部署不必要的文件。
  2. 再试一次
  3. 重置网站
  4. 再试一次
  5. IISRESET

我认为最简单的方法是将这些dll设为CopyLocal为true。 我假设这些dll是从程序文件文件夹中提取出来的。 尝试将它们标记为copylocal true并执行部署。尝试停止在本地计算机上运行的任何IIS本地进程。

注意你没有运行带有文件锁的那些新奇的云备份服务 – 而且你也没有在资源管理器或DLL检查工具中打开它们。

我认为MS没有为这个问题做出更好的规定,这有点荒谬。 我发现9次中有10次我的部署运行得很好,但随后我们的流量增加了10次就变成了1次。

我将用以下方法解决问题:

  • 两个应用程序MySite.AMySite.B ,其中一次只运行一个。
  • 然后我总是部署到hibernate站点。
  • 如果在部署期间出现问题,则永远不会导致整个站点停机。
  • 如果部署后出现重大问题,您可以轻松恢复。

我不太确定我是如何实现它的,但我认为这是我需要做的。