【问题标题】:App_Offline in MSBuild Remote Web DeployMSBuild 远程 Web 部署中的 App_Offline
【发布时间】:2012-02-21 23:11:04
【问题描述】:

我的 MSBuild 脚本中有以下任务要使用 Web 部署(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 属性或任何其他脚本调整来实现它?

提前致谢。

【问题讨论】:

    标签: msbuild msdeploy web-deployment webdeploy


    【解决方案1】:

    我最近刚刚在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

    【讨论】:

    • 我已经把它放在了我的博客列表中,谢谢。
    • msbuild.exe 现在有一个名为 -enableRule:AppOffline 的参数,用于在发布站点之前使应用程序脱机。有没有办法从 msbuild 调用它?
    • @SergeyZwezdin WebDeploy v 3.0(在服务器上)确实有这个选项。见iis.net/learn/publish/deploying-application-packages/…。它目前不支持自定义离线文件。
    • 谢谢赛义德。它几乎对我有用,除了 msbuild 调用不添加密码。在删除部分,“$(Password)”不应该是“%(_AoDeleteAppOfflineDestProviderSetting.Password)”。我也试过了,还是不加密码
    • @SzilardD 似乎 $(MSDeployPath) 和 $(Password) 会导致问题。该脚本在我的 VS2012 项目中没有找到这些。我在github 上创建了一个拉取请求以包含 $(MSDeployPath)。如果您在脚本或 pubxml 中将 yourpw 添加到 PropertyGroup,则 $(Password) 将被识别。
    【解决方案2】:

    WebDeploy v3.0 现在支持此功能。您只需将此行添加到“Properties\PublishProfiles”中的发布配置文件中

    <EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
    

    因此,生成的发布配置文件将如下所示。

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
        <WebPublishMethod>MSDeploy</WebPublishMethod>
        <MSDeployServiceURL>(removed)</MSDeployServiceURL>
        <DeployIisAppPath>Default Web Site</DeployIisAppPath>
        <AllowUntrustedCertificate>True</AllowUntrustedCertificate>
        <SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
        <DeployAsIisApp>False</DeployAsIisApp>
        <MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
        <UserName>sayedha</UserName>
        <ExcludeApp_Data>False</ExcludeApp_Data>
        <_SavePWD>True</_SavePWD>
      </PropertyGroup>
    </Project>
    

    我已经对此进行了测试,它确实在部署期间使我的应用程序脱机,但不幸的是,我仍然偶尔会收到“PrecompiledApp.config is in used”错误。

    更多信息可以在这里找到:http://blogs.msdn.com/b/webdev/archive/2013/10/30/web-publishing-updates-for-app-offline-and-usechecksum.aspx

    【讨论】:

      猜你喜欢
      • 2017-12-15
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      相关资源
      最近更新 更多