2011-09-15 67 views
18

我正在使用Web Deploy打包和部署我的產品的網站。特別是,我在我的解決方案中有兩個不同的項目,我使用這種方法進行部署。使用MsBuild生成定製的MsDeploy清單(包目標)

我有一個解決方案(一個Windows服務),也需要安裝在Web服務器上的第三個項目。

我知道我可以編寫自定義清單(針對dirPath,filePathrunCommand提供程序),並直接調用MsDeploy進行部署。但我想利用現有的MsBuild任務來儘可能打包我的服務。

我看到是有可能通過的MSBuild目標做清單文件的一些定製:

http://social.msdn.microsoft.com/Forums/en/msbuild/thread/1044058c-f762-456b-8a68-b0863027ce47

特別是通過使用MsDeploySourceManifest項目。

在戳穿相應的.targets文件後,如果我使用Package目標,它看起來像contentPathiisApp將被附加到我的清單中。理想情況下,我只想複製程序集(或目錄),可能設置ACL,然後在服務上執行installutil.exe。

是否可以通過編輯我的csproj文件來完全自定義由Package目標生成的清單?

如果沒有,是否有一個簡單的方法來建立一個新的目標,將執行相當於Package,但允許我吐出一個完全自定義的清單?

+0

您是否得到了答案? – musica

+0

@Graci:我做到了。本週我正在完成此工作項目,並在完成所有工作後發佈答案。關鍵概念是創建一個自定義的'.targets'文件,使用您的自定義目標來添加'runCommand'提供程序條目以執行自定義批處理文件(用於停止/卸載服務以及安裝/啓動它),添加自定義參數。 xml文件添加到項目中,並設置某些標誌,如「IncludeIisSettingsOnPublish = False」和「IncludeIisSettingsOnPublish = False」。哦,免費的SlowCheetah非網頁轉換擴展也有幫助。 –

+0

@Merlyn:如果你有時間分享你的解決方案,從你最後的評論中聽起來就像你已經覆蓋好了,那將是非常棒的。 –

回答

16

對於試圖瞭解其工作原理的人,我還沒有完整的書寫,但現在我已經寫下了如何至少實現此目標。

http://thehappypath.net/2011/11/21/using-msdeploy-for-windows-services/

編輯:鏈接已經死了,現在讓我知道如果你有興趣,我可以在其他地方張貼)。

我的導遊會經過以下總體步驟:

  • 確保服務本身開始安裝時(並不重要,但更容易處理)
  • 的Microsoft.WebApplication.targets文件添加到您的項目,即使你沒有一個web項目。這使得Msbuild目標成爲Package
  • 添加自定義.targets文件到你的項目,建立一個自定義的MSBuild包清單
  • 添加一些批處理腳本到你的項目停止/卸載和安裝的服務
  • 添加的parameters.xml文件來支持更改目標部署目錄更輕鬆一點
  • 設置應用程序。

    msbuild MyProject.csproj /t:Package /p:Configuration=Debug 
    

    你可以配置所得到的包裝使用此命令行:

    MyService.Deploy.cmd /Y /M:mywebserver -allowUntrusted 
    

    最無證部分使用the SlowCheetah Visual Studio addon

然後你就可以打包使用此命令行您的項目配置的轉換(除了我的指南)正在創建自定義清單。這裏是我當前文件的轉儲(注意,它仍然有點bug,但可以修復 - 請參閱此問題:MsDeploy remoting executing manifest twice - 並儘量保持使用只有直接批處理文件爲runCommand)。

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" DefaultTargets="Build" 
     xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <!-- This file must be included before Microsoft.Web.Publishing.targets so we can hook into BeforeAddIisSettingAndFileContentsToSourceManifest --> 

    <PropertyGroup> 

    <!-- Include our targets --> 
    <IncludeStopServiceCommand>True</IncludeStopServiceCommand> 
    <IncludeSetCustomAclsProvider>True</IncludeSetCustomAclsProvider> 
    <IncludeInstallServiceCommand>True</IncludeInstallServiceCommand> 
    <IncludeMoveAppConfigToCorrectPackagePath>True</IncludeMoveAppConfigToCorrectPackagePath> 

    <!-- Uncomment to enable more verbose MsBuild logging --> 
    <!-- <EnablePackageProcessLoggingAndAssert>True</EnablePackageProcessLoggingAndAssert> --> 

    <!-- Enable web.config transform, but hack it to work for app.config --> 
    <ProjectConfigFileName>app.config</ProjectConfigFileName> 
    <TransformWebConfigEnabled>True</TransformWebConfigEnabled> 
    <UseParameterizeToTransformWebConfig>True</UseParameterizeToTransformWebConfig> 

    <!-- Enable web project packaging, but hack it to work for non-web app --> 
    <DeployAsIisApp>False</DeployAsIisApp> 
    <IncludeIisSettingsOnPublish>False</IncludeIisSettingsOnPublish> 
    <IncludeSetAclProviderOnDestination>False</IncludeSetAclProviderOnDestination> 
    <DisableAllVSGeneratedMSDeployParameter>True</DisableAllVSGeneratedMSDeployParameter> 

    <!-- Insert our custom targets into correct places in build process --> 
    <BeforeAddIisSettingAndFileContentsToSourceManifest Condition="'$(BeforeAddIisSettingAndFileContentsToSourceManifest)'==''"> 
     $(BeforeAddIisSettingAndFileContentsToSourceManifest); 
     AddStopServiceCommand; 
    </BeforeAddIisSettingAndFileContentsToSourceManifest> 

    <AfterAddIisSettingAndFileContentsToSourceManifest Condition="'$(AfterAddIisSettingAndFileContentsToSourceManifest)'==''"> 
     $(AfterAddIisSettingAndFileContentsToSourceManifest); 
     AddSetCustomAclsProvider; 
     AddInstallServiceCommand; 
    </AfterAddIisSettingAndFileContentsToSourceManifest> 

    <OnAfterCopyAllFilesToSingleFolderForPackage Condition="'$(OnAfterCopyAllFilesToSingleFolderForPackage)'==''"> 
     $(OnAfterCopyAllFilesToSingleFolderForPackage); 
     MoveAppConfigToCorrectPackagePath; 
    </OnAfterCopyAllFilesToSingleFolderForPackage> 

    </PropertyGroup> 

    <!-- Custom targets --> 
    <Target Name="AddStopServiceCommand" Condition="'$(IncludeStopServiceCommand)'=='true'"> 
    <Message Text="Adding runCommand to stop the running Service" /> 
    <ItemGroup> 

     <MsDeploySourceManifest Include="runCommand"> 
     <path>$(_MSDeployDirPath_FullPath)\bin\servicestop.bat</path> 
     <waitInterval>20000</waitInterval> 
     <AdditionalProviderSettings>waitInterval</AdditionalProviderSettings> 
     </MsDeploySourceManifest> 

    </ItemGroup> 
    </Target> 

    <Target Name="AddSetCustomAclsProvider" Condition="'$(IncludeSetCustomAclsProvider)'=='true'"> 
    <ItemGroup> 

     <MsDeploySourceManifest Include="setAcl"> 
     <Path>$(_MSDeployDirPath_FullPath)</Path> 
     <setAclUser>LocalService</setAclUser> 
     <setAclAccess>FullControl</setAclAccess> <!-- Todo: Reduce these permissions --> 
     <setAclResourceType>Directory</setAclResourceType> 
     <AdditionalProviderSettings>setAclUser;setAclAccess;setAclResourceType</AdditionalProviderSettings> 
     </MsDeploySourceManifest> 

    </ItemGroup> 
    </Target> 

    <Target Name="AddInstallServiceCommand" Condition="'$(IncludeInstallServiceCommand)'=='true'"> 
    <Message Text="Adding runCommand to install the Service" /> 
    <ItemGroup> 

     <MsDeploySourceManifest Include="runCommand"> 
     <path>cmd.exe /c $(_MSDeployDirPath_FullPath)\bin\serviceinstall.bat</path> 
     <waitInterval>20000</waitInterval> 
     <dontUseCommandExe>false</dontUseCommandExe> 
     <AdditionalProviderSettings>waitInterval;dontUseCommandExe</AdditionalProviderSettings> 
     </MsDeploySourceManifest> 

    </ItemGroup> 
    </Target> 

    <Target Name="MoveAppConfigToCorrectPackagePath" 
      Condition="'$(IncludeMoveAppConfigToCorrectPackagePath)'=='true'"> 
    <PropertyGroup> 
     <OriginalAppConfigFilename>$(_PackageTempDir)\App.Config</OriginalAppConfigFilename> 
     <TargetAppConfigFilename>$(_PackageTempDir)\bin\$(TargetFileName).config</TargetAppConfigFilename> 
    </PropertyGroup> 

    <Copy SourceFiles="$(OriginalAppConfigFilename)" DestinationFiles="$(TargetAppConfigFilename)" 
      Condition="Exists($(OriginalAppConfigFilename))" /> 
    <Delete Files="$(OriginalAppConfigFilename)" 
      Condition="Exists($(OriginalAppConfigFilename))" /> 
    </Target> 

</Project> 
+0

爲什麼你在步驟中列出了它們的原始值,以前你斷言它們是空的?由於某種可怕的事情,它真的是不可思議嗎?我的意思是,一些屬性看起來像' $(prop);擴展',所以它們都'使用,如果沒有設置'和'注入,而不是壓倒一切'。只有在沒有附加任何東西的情況下,您的樣本纔會自行附加它,並且同時它會嘗試保留原始內容(假設它在其之前是空的)。我會認爲無論那種條件,還是'concat'行爲都不需要。 – quetzalcoatl

+0

無論如何,偉大的工作!在找到你的代碼片段之前,我剛剛找到了類似的補丁/擴展,所以可能這是唯一的方法。順便說一句。我還發現'TransformWebConfigEnabled'在默認情況下具有'true',所以它可能也會被修剪。 Btw2。你有沒有嘗試過app.config的參數化?由於'webconfig/appconfig'被移動和重命名,應用SetParameters.xml中的值是否存在問題? – quetzalcoatl

+0

嗯..是的,我很肯定會有問題,因爲在包內的'parameters.xml'中有明確的參考舊的'App.config'。我認爲'ImportParametersFiles'目標需要一些額外的修復,或者接近這個目標。 – quetzalcoatl

相關問題