msbuild - MSBuild 远程 Web 部署中的 App_Offline

标签 msbuild msdeploy web-deployment webdeploy

我的 MSBuild 脚本中有以下任务要使用 Web Deploy(MSDeploy 服务)部署到远程服务器:

  <Target Name="Deploy">
    <MSBuild
            Projects="$(SolutionFile)"
            Properties="Configuration=Release; DeployOnBuild=True; 
              DeployTarget=MsDeployPublish; MSDeployPublishMethod=WMSvc; 
              MsDeployServiceUrl=$(DeployServiceUrl); 
              DeployIisAppPath=$(DeployIisAppPath); 
              UserName=$(DeployUserName); Password=$(DeployPassword); 
              CreatePackageOnPublish=True; AllowUntrustedCertificate=True" />
  </Target>

它工作正常。但是,我想在部署应用程序之前放置一个 app_offline.htm 文件(在远程服务器上),并在部署后(或出错时)删除 app_offline.htm 文件。是否有 MSBuild 属性或任何其他脚本调整来实现它?

提前致谢。

最佳答案

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

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

由于 Web Deploy 不支持此功能,因此难度会更大一些,并且需要我们执行以下步骤:

  • 发布 app_offline.htm
  • 发布应用程序,并确保 app_offline.htm 包含在正在发布的有效负载中
  • 删除 app_offline.htm

  • 1 将在发布过程开始之前使应用脱机。

    2 将确保当我们发布 app_offline.htm 时不会被删除(因此保持应用程序离线)

    3 将删除 app_offline.htm 并使网站重新联机

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

    enter image description here

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

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

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

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

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

    资源
  • The latest version of my AppOffline wpp.targets file
  • ScottGu’s blog on app_offline.htm
  • 关于msbuild - MSBuild 远程 Web 部署中的 App_Offline,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9059109/

    相关文章:

    visual-c++ - 在 C++ 项目中使用 x86 平台

    .net - msdeploy 忽略 .hgignore

    linux - 是否有必要为不同的用户运行多个 uWSGI 网站?

    c# - 如何在 msbuild 命令行参数中设置 publishName/AssemblyName?

    iis - 如何防止 MSDeploy 任务重建程序集?

    c# - 使用 TeamCity 部署网站项目

    asp.net - Visual Studio 发布配置文件 - 为什么不在源代码管理中进行跟踪?

    css - 向 html 链接标记添加预览

    msbuild - 使用 msbuild 删除空目录

    msbuild - MS Deploy 可以打包和转换,但不能部署吗?