2011-01-20 64 views

回答

5

(另一種方法)

的msdeploy包裝一個MSBuild過程中,僅僅指剛調用運行您的項目。

TransformXml是.csproj或.vsproj構建的一個包含任務。

只需修改您的構建過程即可在您需要的任何文件上調用該任務。

例如,我們所要做的就是寫一個自定義的目標

<Target Name="TransformFile"> 

    <TransformXml Source="$(DestinationPath)\$(Sourcefile)" 
     Transform="$(DestinationPath)\$(TransformFile)" 
     Destination="$(DestinationPath)\$(DestFile)" /> 
    </Target> 

然後修改您的.csproj來發布任務調用之前運行此。

<CallTarget Targets="TransformFile" 
    Condition="'$(CustomTransforms)'=='true'" /> 
2

簡短回答:是的,你可以。但這是「困難的」。

龍答: 當我們部署網站的目的地,我們有平常web.test.config和web.prod.config。這工作得很好,直到我們引入了log4net.test.config和log4net.prod.config。 MSBuild不會自動通過並替換所有這些。它只會做web.config的。

如果你想要堅持到最後的代碼片段。它顯示了取一個配置並替換它的功能。但是......如果我描述整個過程,這會更有意義。

的過程:

  1. 的MSBuild使得網站的壓縮文件包。
  2. 我們寫了一個自定義的.net應用程序,它將採用該zip文件並對每個文件進行配置替換。重新保存壓縮文件。
  3. 執行msdeploy命令來部署打包文件。

MSbuild不會自動替換所有額外的配置。有趣的是MSBuild將刪除任何「額外」配置。所以你的log4net.test.config在構建完成後會消失。所以你必須做的第一件事是告訴msdbuild保持這些額外的文件。

你必須修改vbProj文件,包括一個新的設置:

<AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings> 

打開Web應用程序的vbProj文件到您喜歡的文本編輯器。導航到您希望它應用的每個部署配置(發佈,產品,調試等)並將其添加到其中。這是我們的「發佈」配置的一個例子。

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    ... 
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> 
    <DebugType>pdbonly</DebugType> 
    <DefineDebug>false</DefineDebug> 
    <DefineTrace>true</DefineTrace> 
    <Optimize>true</Optimize> 
    <OutputPath>bin\</OutputPath> 
    <DocumentationFile>Documentation.xml</DocumentationFile> 
    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022,42353,42354,42355</NoWarn> 
    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> 
    <DeployIisAppPath>IISAppPath</DeployIisAppPath> 
    <AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings> 
    </PropertyGroup> 
    ... 
</Project> 

所以,現在msbduild將建立項目,並保留這些額外的文件,而不是做替換。現在你必須手動完成它們。

我們寫了一個.net應用程序,它將監視這些新的zip文件。我編寫了一些代碼,它將遍歷整個zip包,並找到與{configname}。{env} .config匹配的任何配置。它會提取它們,替換它們,然後放回去。要進行實際替換,我們使用與MSDeploy使用的相同的DLL。我也使用Ionic.Zip來做zip文件。

所以添加引用:

Microsoft.Build.dll 
Microsoft.Build.Engine.dll 
Microsoft.Web.Publishing.Tasks (possibly, not sure if you need this or not) 

導入:

Imports System.IO 
Imports System.Text.RegularExpressions 
Imports Microsoft.Build.BuildEngine 
Imports Microsoft.Build 

這裏是通過壓縮文件

specificpackage = "mypackagedsite.zip" 
configenvironment = "DEV" 'stupid i had to pass this in, but it's the environment in web.dev.config 

Directory.CreateDirectory(tempdir) 

Dim fi As New FileInfo(specificpackage) 

'copy zip file to temp dir 
Dim tempzip As String = tempdir & fi.Name 

File.Copy(specificpackage, tempzip) 

''extract configs to merge from file into temp dir 
'regex for the web.config 
'regex for the web.env.config 
'(?<site>\w+)\.(?<env>\w+)\.config$ 

Dim strMainConfigRegex As String = "/(?<configtype>\w+)\.config$" 
Dim strsubconfigregex As String = "(?<site>\w+)\.(?<env>\w+)\.config$" 
Dim strsubconfigregex2 As String = "(?<site>\w+)\.(?<env>\w+)\.config2$" 

Dim MainConfigRegex As New Regex(strMainConfigRegex, RegexOptions.Compiled Or RegexOptions.IgnoreCase) 
Dim SubConfigRegex As New Regex(strsubconfigregex, RegexOptions.Compiled Or RegexOptions.IgnoreCase) 
Dim SubConfigRegex2 As New Regex(strsubconfigregex2, RegexOptions.Compiled Or RegexOptions.IgnoreCase) 

Dim filetoadd As New Dictionary(Of String, String) 
Dim filestoremove As New List(Of ZipEntry) 
Using zip As ZipFile = ZipFile.Read(tempzip) 
    For Each entry As ZipEntry In From a In zip.Entries Where a.IsDirectory = False 
     For Each myMatch As Match In MainConfigRegex.Matches(entry.FileName) 
      If myMatch.Success Then 
       'found main config. 
       're-loop through, find any that are in the same dir as this, and also match the config name 
       Dim currentdir As String = Path.GetDirectoryName(entry.FileName) 
       Dim conifgmatchname As String = myMatch.Groups.Item("configtype").Value 

       For Each subentry In From b In zip.Entries Where b.IsDirectory = False _ 
            And UCase(Path.GetDirectoryName(b.FileName)) = UCase(currentdir) _ 
            And (UCase(Path.GetFileName(b.FileName)) = UCase(conifgmatchname & "." & configenvironment & ".config") Or 
              UCase(Path.GetFileName(b.FileName)) = UCase(conifgmatchname & "." & configenvironment & ".config2")) 

        entry.Extract(tempdir) 
        subentry.Extract(tempdir) 

        'Go ahead and do the transormation on these configs 
        Dim newtransform As New doTransform 
        newtransform.tempdir = tempdir 
        newtransform.filename = entry.FileName 
        newtransform.subfilename = subentry.FileName 
        Dim t1 As New Threading.Tasks.Task(AddressOf newtransform.doTransform) 
        t1.Start() 
        t1.Wait() 
        GC.Collect() 
        'sleep here because the build engine takes a while. 
        Threading.Thread.Sleep(2000) 
        GC.Collect() 

        File.Delete(tempdir & entry.FileName) 
        File.Move(tempdir & Path.GetDirectoryName(entry.FileName) & "/transformed.config", tempdir & entry.FileName) 
        'put them back into the zip file 
        filetoadd.Add(tempdir & entry.FileName, Path.GetDirectoryName(entry.FileName)) 
        filestoremove.Add(entry) 
       Next 
      End If 
     Next 
    Next 

    'loop through, remove all the "extra configs" 
    For Each entry As ZipEntry In From a In zip.Entries Where a.IsDirectory = False 

     Dim removed As Boolean = False 

     For Each myMatch As Match In SubConfigRegex.Matches(entry.FileName) 
      If myMatch.Success Then 
       filestoremove.Add(entry) 
       removed = True 
      End If 
     Next 
     If removed = False Then 
      For Each myMatch As Match In SubConfigRegex2.Matches(entry.FileName) 
       If myMatch.Success Then 
        filestoremove.Add(entry) 
       End If 
      Next 
     End If 
    Next 

    'delete them 
    For Each File In filestoremove 
     zip.RemoveEntry(File) 
    Next 

    For Each f In filetoadd 
     zip.AddFile(f.Key, f.Value) 
    Next 
    zip.Save() 
End Using 

最後,但最重要的家紡代碼是我們實際上做了web.configs的替換。

Public Class doTransform 
    Property tempdir As String 
    Property filename As String 
    Property subfilename As String 
    Public Function doTransform() 
     'do the config swap using msbuild 
     Dim be As New Engine 
     Dim BuildProject As New BuildEngine.Project(be) 
     BuildProject.AddNewUsingTaskFromAssemblyFile("TransformXml", "$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll") 
     BuildProject.Targets.AddNewTarget("null") 
     BuildProject.AddNewPropertyGroup(True) 
     DirectCast(BuildProject.PropertyGroups(0), Microsoft.Build.BuildEngine.BuildPropertyGroup).AddNewProperty("GenerateResourceNeverLockTypeAssemblies", "true") 

     Dim bt As BuildTask 
     bt = BuildProject.Targets("null").AddNewTask("TransformXml") 

     bt.SetParameterValue("Source", tempdir & filename) 
     bt.SetParameterValue("Transform", tempdir & subfilename) 
     bt.SetParameterValue("Destination", tempdir & Path.GetDirectoryName(filename) & "/transformed.config") 
     'bt.Execute() 
     BuildProject.Build() 
     be.Shutdown() 

    End Function 

End Class 

就像我說的...這很難但它可以做到。

+0

優秀/全面的答案,但你可以用MsBuild來完成所有這些。看到我的回覆。如果「額外」文件是一個問題,你只需要修改包含輸入/輸出文件的ItemGroups,這些文件將進入Publish/Package調用 – 2011-02-08 19:04:00

+0

是好主意。在我的情況下,只有問題是我們有15個站點使用不同的配置等來完成同樣的事情。所以我在部署時建立了這個「做它」。你的很簡單。 – 2011-02-08 21:07:14

3

泰勒的回答並不適合我,他也沒有提供進一步的細節。所以我去探索Microsoft.Web.Publishing.targets文件來尋找解決方案。可以將以下MSBuild Target添加到項目文件以轉換根應用程序目錄中的所有其他配置文件。享受:)

<Target Name="TransformOtherConfigs" AfterTargets="CollectWebConfigsToTransform"> 
<ItemGroup> 
    <WebConfigsToTransform Include="@(FilesForPackagingFromProject)" 
          Condition="'%(FilesForPackagingFromProject.Extension)'=='.config'" 
          Exclude="*.$(Configuration).config;$(ProjectConfigFileName)"> 
    <TransformFile>%(RelativeDir)%(Filename).$(Configuration).config</TransformFile> 
    <TransformOriginalFile>$(TransformWebConfigIntermediateLocation)\original\%(DestinationRelativePath)</TransformOriginalFile> 
    <TransformOutputFile>$(TransformWebConfigIntermediateLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile> 
    <TransformScope>$([System.IO.Path]::GetFullPath($(_PackageTempDir)\%(DestinationRelativePath)))</TransformScope> 
    </WebConfigsToTransform> 
    <WebConfigsToTransformOuputs Include="@(WebConfigsToTransform->'%(TransformOutputFile)')" /> 
</ItemGroup> 
</Target> 
1

只需添加到這個awnser,以修改其他文件不是與msdeploy(webdeploy)發表了應用程序的web.config可以設置在的parameters.xml文件scope屬性該項目的根:

<parameters> 
    <parameter name="MyAppSetting" defaultvalue="_defaultValue_"> 
    <parameterentry match="/configuration/appSettings/add[@key='MyAppSetting']/@value" scope=".exe.config$" kind="XmlFile"> 
    </parameterentry> 
    </parameter> 
</parameters> 

scope是將用來尋找文件到match的XPath適用於正則表達式。我還沒有廣泛地嘗試過這一點,但據我所知,它只是用後面提供的值替換xpath匹配的內容。

也有可用於kind,將有超過一個XPath不同的行爲,見https://technet.microsoft.com/en-us/library/dd569084(v=ws.10).aspx的細節

其他值

注:這適用於當您正在使用的parameters.xml來,而不是當使用web.config.Debug/Release文件