【问题标题】:Is there a way to make the VS2010 publish wizard to copy App_offline.htm while it is publishing the site?有没有办法让 VS2010 发布向导在发布站点时复制 App_offline.htm?
【发布时间】:2010-09-02 19:18:34
【问题描述】:

看到Hanselman "You are doing it wrong" video之后,我开始使用VS2010的Web Publish功能。

我真正缺少的是网站有时会在网站发布时出错,因为该功能不会将app_offline.htm 文件复制到服务器。

我不想开始使用 MSDeploy 脚本,因为我有几个站点并且希望保持简单。

也许有一个简单的调整来告诉向导复制然后删除文件。

【问题讨论】:

  • 嘿——这听起来很熟悉。你有没有找到解决这个问题的方法?
  • 也许斯科特做错了并且不知道。 ;-)
  • 当我从 VS2010 发布时,它会很好地复制 app_offline.htm 文件,然后在完成后将其删除。
  • @Chevex:想评论一下你是怎么做到的?文件放在哪里?您使用什么选项?
  • app_offline 只有在您选择在发布前删除所有文件时才会被推送。运行替换发布时不会推送 app_offline。

标签: asp.net visual-studio-2010 deployment


【解决方案1】:

app_offline.htm 仅在您选择发布前删除所有文件时才会推送。运行替换发布时不会推送 app_offline.htm。

【讨论】:

  • 这是一个好的开始,因为它表明该工具支持推送文件。当您使用更常见的选项仅复制新文件时,我们可以找到使其工作的方法...
【解决方案2】:

此问题与App_Offline in MSBuild Remote Web Deploy 重复,但我已将答案粘贴在下面。 MSDeploy v3 直接支持 app_offline,但双方都需要 MSDeploy v3。我们尚未更新 VS Web Publish 体验以便能够利用这一点,但我们会在某个时候进行更新。

我最近刚刚在http://sedodream.com/2012/01/08/HowToTakeYourWebAppOfflineDuringPublishing.aspx 上写了一篇博客。它比它应该的更困难,我正在努力为以后的版本简化它。无论如何,我已经为您粘贴了所有内容。

我收到了一封客户电子邮件,询问他们如何在 Visual Studio 发布的整个持续时间内使他们的 Web 应用程序/站点脱机。使您的站点脱机的一种简单方法是将 app_offline.htm 文件放在站点根目录中。有关这方面的更多信息,您可以阅读 ScottGu 的帖子,链接在下面的资源部分。不幸的是,Web Deploy 本身不支持这个。如果您希望 Web Deploy(又名 MSDeploy)原生支持此功能,请在 http://aspnet.uservoice.com/forums/41199-general/suggestions/2499911-take-my-site-app-offline-during-publishing 投票。

由于 Web Deploy 不支持这一点,它会有点困难,它需要我们执行以下步骤:

  1. 发布 app_offline.htm
  2. 发布应用,并确保 app_offline.htm 包含在要发布的负载中
  3. 删除 app_offline.htm

1 将在发布过程开始之前使应用离线。

2 将确保在我们发布时 app_offline.htm 不会被删除(从而使应用保持离线状态)

3 将删除 app_offline.htm 并使网站恢复在线

现在我们知道需要做什么,让我们看看实现。首先是简单的部分。在您的 Web 应用程序项目 (WAP) 中创建一个名为 app_offline-template.htm 的文件。这将是最终成为目标服务器上的 app_offline.htm 文件的文件。如果您将其留空,您的用户将收到一条通用消息,说明应用程序已离线,但您最好将 static HTML(无 ASP.NET 标记)放置在该文件中,让用户知道该站点将恢复,以及您认为与您的用户相关的任何其他信息。添加此文件时,您应该在“属性”网格中将“构建操作”更改为“无”。这将确保此文件本身未发布/打包。由于文件以 .htm 结尾,默认情况下会发布。见下图。

现在是最难的部分。对于 Web 应用程序项目,我们有一个挂钩到发布/打包过程,我们称之为“wpp.targets”。如果您想扩展您的发布/打包过程,您可以在与项目文件本身相同的文件夹中创建一个名为 {ProjectName}.wpp.targets 的文件。这是我创建的文件,您可以将内容复制并粘贴到您的 wpp.targets 文件中。我将解释重要部分,但想发布整个文件以说服您。注意:你可以从我的 github repo 中获取这个文件的最新版本,链接在下面的资源部分。

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="InitalizeAppOffline">
    <!-- 
    This property needs to be declared inside of target because this is imported before
    the MSDeployPath property is defined as well as others -->
    <PropertyGroup>
      <MSDeployExe Condition=" '$(MSDeployExe)'=='' ">$(MSDeployPath)msdeploy.exe</MSDeployExe>
    </PropertyGroup>    
  </Target>

  <PropertyGroup>
    <PublishAppOfflineToDest>
      InitalizeAppOffline;
    </PublishAppOfflineToDest>
  </PropertyGroup>

  <!--
    %msdeploy% 
      -verb:sync 
      -source:contentPath="C:\path\to\app_offline-template.htm" 
      -dest:contentPath="Default Web Site/AppOfflineDemo/app_offline.htm"
  -->

  <!--***********************************************************************
  Make sure app_offline-template.htm gets published as app_offline.htm
  ***************************************************************************-->
  <Target Name="PublishAppOfflineToDest" 
          BeforeTargets="MSDeployPublish" 
          DependsOnTargets="$(PublishAppOfflineToDest)">
    <ItemGroup>
      <_AoPubAppOfflineSourceProviderSetting Include="contentPath">
        <Path>$(MSBuildProjectDirectory)\app_offline-template.htm</Path>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <WebServerAppHostConfigDirectory>$(_MSDeploySourceWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeploySourceWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeploySourceWebServerDirectory)</WebServerDirectory>
      </_AoPubAppOfflineSourceProviderSetting>

      <_AoPubAppOfflineDestProviderSetting Include="contentPath">
        <Path>"$(DeployIisAppPath)/app_offline.htm"</Path>
        <ComputerName>$(_PublishMsDeployServiceUrl)</ComputerName>
        <UserName>$(UserName)</UserName>
        <Password>$(Password)</Password>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <IncludeAcls>False</IncludeAcls>
        <AuthType>$(AuthType)</AuthType>
        <WebServerAppHostConfigDirectory>$(_MSDeployDestinationWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeployDestinationWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeployDestinationWebServerDirectory)</WebServerDirectory>
      </_AoPubAppOfflineDestProviderSetting>
    </ItemGroup>

    <MSdeploy
          MSDeployVersionsToTry="$(_MSDeployVersionsToTry)"
          Verb="sync"
          Source="@(_AoPubAppOfflineSourceProviderSetting)"
          Destination="@(_AoPubAppOfflineDestProviderSetting)"
          EnableRule="DoNotDeleteRule"
          AllowUntrusted="$(AllowUntrustedCertificate)"
          RetryAttempts="$(RetryAttemptsForDeployment)"
          SimpleSetParameterItems="@(_AoArchivePublishSetParam)"
          ExePath="$(MSDeployPath)" />
  </Target>

  <!--***********************************************************************
  Make sure app_offline-template.htm gets published as app_offline.htm
  ***************************************************************************-->
  <!-- We need to create a replace rule for app_offline-template.htm->app_offline.htm for when the app get's published -->
  <ItemGroup>
    <!-- Make sure not to include this file if a package is being created, so condition this on publishing -->
    <FilesForPackagingFromProject Include="app_offline-template.htm" Condition=" '$(DeployTarget)'=='MSDeployPublish' ">
      <DestinationRelativePath>app_offline.htm</DestinationRelativePath>
    </FilesForPackagingFromProject>

    <!-- This will prevent app_offline-template.htm from being published -->
    <MsDeploySkipRules Include="SkipAppOfflineTemplate">
      <ObjectName>filePath</ObjectName>
      <AbsolutePath>app_offline-template.htm</AbsolutePath>
    </MsDeploySkipRules>
  </ItemGroup>

  <!--***********************************************************************
  When publish is completed we need to delete the app_offline.htm
  ***************************************************************************-->
  <Target Name="DeleteAppOffline" AfterTargets="MSDeployPublish">
    <!--
    %msdeploy% 
      -verb:delete 
      -dest:contentPath="{IIS-Path}/app_offline.htm",computerName="...",username="...",password="..."
    -->
    <Message Text="************************************************************************" />
    <Message Text="Calling MSDeploy to delete the app_offline.htm file" Importance="high" />
    <Message Text="************************************************************************" />

    <ItemGroup>
      <_AoDeleteAppOfflineDestProviderSetting Include="contentPath">
        <Path>$(DeployIisAppPath)/app_offline.htm</Path>
        <ComputerName>$(_PublishMsDeployServiceUrl)</ComputerName>
        <UserName>$(UserName)</UserName>
        <Password>$(Password)</Password>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <AuthType>$(AuthType)</AuthType>
        <WebServerAppHostConfigDirectory>$(_MSDeployDestinationWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeployDestinationWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeployDestinationWebServerDirectory)</WebServerDirectory>
      </_AoDeleteAppOfflineDestProviderSetting>
    </ItemGroup>

    <!-- 
    We cannot use the MSDeploy/VSMSDeploy tasks for delete so we have to call msdeploy.exe directly.
    When they support delete we can just pass in @(_AoDeleteAppOfflineDestProviderSetting) as the dest
    -->
    <PropertyGroup>
      <_Cmd>"$(MSDeployExe)" -verb:delete -dest:contentPath="%(_AoDeleteAppOfflineDestProviderSetting.Path)"</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.ComputerName)' != '' ">$(_Cmd),computerName="%(_AoDeleteAppOfflineDestProviderSetting.ComputerName)"</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.UserName)' != '' ">$(_Cmd),username="%(_AoDeleteAppOfflineDestProviderSetting.UserName)"</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.Password)' != ''">$(_Cmd),password=$(Password)</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.AuthType)' != ''">$(_Cmd),authType="%(_AoDeleteAppOfflineDestProviderSetting.AuthType)"</_Cmd>
    </PropertyGroup>

    <Exec Command="$(_Cmd)"/>
  </Target>  
</Project>

1 发布 app_offline.htm

#1 的实现包含在目标 PublishAppOfflineToDest 中。我们需要执行的 msdeploy.exe 命令是。

msdeploy.exe 
    -source:contentPath='C:\Data\Personal\My Repo\sayed-samples\AppOfflineDemo01\AppOfflineDemo01\app_offline-template.htm' 
    -dest:contentPath='"Default Web Site/AppOfflineDemo/app_offline.htm"',UserName='sayedha',Password='password-here',ComputerName='computername-here',IncludeAcls='False',AuthType='NTLM' -verb:sync -enableRule:DoNotDeleteRule

为了做到这一点,我将利用 MSDeploy 任务。在 PublishAppOfflineToDest 目标内部,您可以看到如何通过为源和目标创建项目来完成此操作。

2 发布应用,并确保 app_offline.htm 包含在要发布的负载中

这部分由片段完成

<!--***********************************************************************
Make sure app_offline-template.htm gets published as app_offline.htm
***************************************************************************-->
<!-- We need to create a replace rule for app_offline-template.htm->app_offline.htm for when the app get's published -->
<ItemGroup>
  <!-- Make sure not to include this file if a package is being created, so condition this on publishing -->
  <FilesForPackagingFromProject Include="app_offline-template.htm" Condition=" '$(DeployTarget)'=='MSDeployPublish' ">
    <DestinationRelativePath>app_offline.htm</DestinationRelativePath>
  </FilesForPackagingFromProject>

  <!-- This will prevent app_offline-template.htm from being published -->
  <MsDeploySkipRules Include="SkipAppOfflineTemplate">
    <ObjectName>filePath</ObjectName>
    <AbsolutePath>app_offline-template.htm</AbsolutePath>
  </MsDeploySkipRules>
</ItemGroup>

此处 FilesForPackagingFromProject 的项目值会将您的 app_offline-template.htm 转换为将处理发布的文件夹中的 app_offline.htm。还有一个条件,它只发生在发布期间而不是打包期间。我们不希望 app_offline-template.htm 出现在包中(但如果它出现也不是世界末日)。

MsDeploySkiprules 的元素将确保 app_offline-template.htm 本身不会被发布。这可能不是必需的,但应该不会造成伤害。

3 删除 app_offline.htm

现在我们的应用已经发布,我们需要从目标网络应用中删除 app_offline.htm 文件。 msdeploy.exe 命令是:

%msdeploy% -动词:删除 -dest:contentPath="{IIS-Path}/app_offline.htm",computerName="...",username="...",password="..."

这是在 DeleteAppOffline 目标内部实现的。这个目标将在发布后自动执行,因为我已经包含属性 AfterTargets=”MSDeployPublish”。在该目标中,您可以看到我正在直接构建 msdeploy.exe 命令,看起来 MSDeploy 任务不支持删除动词。

如果您尝试此操作,请在遇到任何问题时告诉我。我正在考虑从中创建一个 Nuget 包,以便您可以安装该包。这需要一些工作,所以如果您对此感兴趣,请告诉我。

资源

  1. The latest version of my AppOffline wpp.targets file
  2. ScottGu’s blog on app_offline.htm

【讨论】:

  • 感谢您的详细回答,很高兴知道您正在使用简化版本!
  • 看来这几乎可以工作,但后来我得到一个 ERROR_USER_NOT_ADMIN 401 Unauthorized。通常这意味着凭据是错误的。查看它正在使用的命令并没有将密码传递给 msdeploy。我该如何解决?
【解决方案3】:

Web Deploy (MSDeploy) v3 supports adding an app_offline.htm file during deployment,但它对您的目的有两个限制:

  • 它使用自己的 app_offline.htm 模板(它支持自定义模板,但它does not work
  • Web 发布管道(Web 部署之上的 MSBuild 堆栈)不支持将自定义规则传递给 MSDeploy,这排除了使用 WPP。

【讨论】:

    猜你喜欢
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-05-19
    相关资源
    最近更新 更多