MSBuild远程Web部署中的App_Offline

时间:2012-01-30 03:47:47

标签: 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属性或任何其他脚本调整来实现它?

提前致谢。

2 个答案:

答案 0 :(得分:22)

我最近在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
  4. 1 会在发布过程开始之前使应用离线。

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

    3 会删除app_offline.htm并将网站重新上线

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

    enter image description here

    现在是困难的部分。对于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

    现在我们的应用程序已发布,我们需要从dest web应用程序中删除app_offline.htm文件。 msdeploy.exe命令为:

    %msdeploy%       -verb:删除       -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

答案 1 :(得分:13)

现在,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 used'错误。

有关此内容的更多信息,请访问:http://blogs.msdn.com/b/webdev/archive/2013/10/30/web-publishing-updates-for-app-offline-and-usechecksum.aspx