32

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

SqlServerTypes\x64\SqlServerSpatial110.dll

SqlServerTypes\x86\msvcr100.dll

SqlServerTypes\x86\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),但发布仍然失败并出现相同的错误。所有其他文件完美发布。

有任何想法吗?

4

5 回答 5

27

您可以在发布期间使您的应用程序脱机,这有望释放文件上的锁定并允许您对其进行更新。

不久前我在博客上写过这个。概述的支持在 Azure SDK 和 Visual Studio 更新中提供。我不记得确切的版本,但如果需要,我可以找到。在那篇博文前后/之后的任何更新都应该没问题。

先决条件:

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

注意:如果您从 CI 服务器发布,则 CI 服务器也需要上述更新

编辑发布配置文件

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

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

<EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>

笔记

需要 ASP.NET

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

可能不起作用的情况

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

如果您添加<EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>并且您的应用程序没有足够快地离线,那么我建议您在发布开始之前将应用程序离线。有几种方法可以远程执行此操作,但这取决于您的设置。如果您只有 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直接调用的脚本,而不是将其集成到项目构建/发布过程中。

于 2015-01-06T03:42:31.060 回答
8

我找到了 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 是通过互操作 LoadLibray 调用手动加载的非托管代码。因此,dll 位于应用程序域的权限之外。

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

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

[DllImport("kernel32.dll", SetLastError = true)]
internal extern static bool FreeLibrary(IntPtr hModule);

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 的应用程序。由于应用程序池可以托管多个应用程序,因此如果另一个应用程序也加载了文件锁,则不会释放它们。这将防止您的部署使用相同的文件锁定错误。

于 2015-09-18T21:38:04.587 回答
1

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

然而,我想问的问题是您是否甚至需要重新部署这些文件?

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

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

  1. 避免部署不必要的文件。
  2. 再试一次
  3. 重置网站
  4. 再试一次
  5. iis重置
于 2015-01-06T03:21:45.960 回答
1

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

于 2015-01-06T03:25:44.950 回答
0

请注意,您没有运行那些正在执行文件锁定的新型云备份服务 - 而且您没有在资源管理器或 DLL 检查工具中打开任何东西。

我认为微软没有为这个问题做出更好的规定有点荒谬。我发现 10 次中有 9 次我的部署工作得很好,但是随着我们的流量增加,这可能会变成 10 次中的 1 次。

我将通过以下方式解决问题:

  • 两个应用程序MySite.AMySite.B,一次只运行一个。
  • 然后我总是部署到休眠站点。
  • 如果在部署过程中出现问题,它永远不会导致整个站点宕机。
  • 如果部署后出现重大问题,您可以很容易地恢复。

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

于 2017-04-14T22:14:33.153 回答