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
添加以下属性。
笔记
ASP.NET必需
在MSDeploy端实现此方法的方法是将app_offline.htm文件放在网站/应用程序的根目录中。 从那里,asp.net运行时将检测到并使您的应用程序脱机。 因此,如果您的网站/应用程序没有启用asp.net,则此function将无效。
它可能无法工作的情况
这样做的实现使得应用程序在发布开始之前可能不会严格脱机。 首先删除app_offline.htm文件,然后MSDeploy将开始发布文件。 它不等待ASP.NET检测文件并实际使其脱机。 因此,您可能遇到仍然遇到文件锁的情况。 默认情况下,VS启用重试,因此通常应用程序将在其中一个重试期间脱机,一切都很好。 在某些情况下,ASP.NET可能需要更长时间才能响应。 这有点棘手。
如果你添加
并且你的应用程序没有很快下线,那么我建议你在发布开始之前使应用程序脱机。 有几种方法可以远程执行此操作,但这取决于您的设置。 如果您只有MSDeploy访问权限,则可以尝试以下顺序:
- 使用
msdeploy.exe
删除app_offline.htm以使您的站点脱机 - 使用
msdeploy.exe
发布您的应用程序(_确保同步不会删除app_offline.htm文件_) - 等待一段时间
- 发布网站
- 使用
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问题,我相信你的问题的答案是:
- 避免部署不必要的文件。
- 再试一次
- 重置网站
- 再试一次
- IISRESET
我认为最简单的方法是将这些dll设为CopyLocal为true。 我假设这些dll是从程序文件文件夹中提取出来的。 尝试将它们标记为copylocal true并执行部署。尝试停止在本地计算机上运行的任何IIS本地进程。
注意你没有运行带有文件锁的那些新奇的云备份服务 – 而且你也没有在资源管理器或DLL检查工具中打开它们。
我认为MS没有为这个问题做出更好的规定,这有点荒谬。 我发现9次中有10次我的部署运行得很好,但随后我们的流量增加了10次就变成了1次。
我将用以下方法解决问题:
- 两个应用程序
MySite.A
和MySite.B
,其中一次只运行一个。 - 然后我总是部署到hibernate站点。
- 如果在部署期间出现问题,则永远不会导致整个站点停机。
- 如果部署后出现重大问题,您可以轻松恢复。
我不太确定我是如何实现它的,但我认为这是我需要做的。