Web.Config transforms outside of Microsoft MSBuild?

时光怂恿深爱的人放手 提交于 2019-11-26 11:57:32

问题


Is it possible to use Microsoft\'s XML document transform, for preparing web.configs, outside of MSBuild? I would like to use PowerShell to do these transform without having to run this through the MSBuild engine. If Microsoft had used standard XSLT it would be easy to do in PowerShell. From what I can tell I have to use their C:\\Program Files (x86)\\MSBuild\\Microsoft\\VisualStudio\\v10.0\\Web\\Microsoft.Web.Publishing.Tasks.dll which requires a build engine. Thanks


回答1:


I created a small function to handle Microsoft's XML Document Transform in PowerShell.

I copied the Microsoft.Web.XmlTransform.dll file from Visual Studio build folder to my script's path, but you can reference it from the source folder if you'd like.

function XmlDocTransform($xml, $xdt)
{
    if (!$xml -or !(Test-Path -path $xml -PathType Leaf)) {
        throw "File not found. $xml";
    }
    if (!$xdt -or !(Test-Path -path $xdt -PathType Leaf)) {
        throw "File not found. $xdt";
    }

    $scriptPath = (Get-Variable MyInvocation -Scope 1).Value.InvocationName | split-path -parent
    Add-Type -LiteralPath "$scriptPath\Microsoft.Web.XmlTransform.dll"

    $xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
    $xmldoc.PreserveWhitespace = $true
    $xmldoc.Load($xml);

    $transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdt);
    if ($transf.Apply($xmldoc) -eq $false)
    {
        throw "Transformation failed."
    }
    $xmldoc.Save($xml);
}

To transform web.config using web.release.config:

XmlDocTransform -xml "Web.config" -xdt "Web.Release.config"

Alternatively, you can use Sayed's self-bootstraping Xml Transform script, which will take care of getting the Microsoft.Xml.Xdt.dll for you:

https://gist.github.com/sayedihashimi/f1fdc4bfba74d398ec5b




回答2:


The logic of the transformation is contained inside of the TransformXml task itself. If you want to call it from code you would have to use the MSBuild API with a mock engine and execute it. I have some code for this if you want.

In your case since you mentioned PowerShell the best thing for you to do is to just create a wrapper MSBuild file to invoke the TransformXml task. I say this because PowerShell is configured to run under .NET 2.0, but the TransformXml task requires .NET 4.0. In order to call it from a dummy MSBuild file you can check my blog at http://sedodream.com/2010/04/26/ConfigTransformationsOutsideOfWebAppBuilds.aspx, but I've also pasted a sample from that link below.

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="TransformXml"
             AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>

    <Target Name="Demo">
        <TransformXml Source="app.config"
                      Transform="Transform.xml"
                      Destination="app.prod.config"/>
    </Target>
</Project>

For mono, this should work (tested on mono 6.4, macos, 2019) :

<Project DefaultTargets="TransformConfig" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask TaskName="TransformXml"
    AssemblyFile="$(MSBuildSDKsPath)/Microsoft.NET.Sdk.Publish/tools/net46/Microsoft.NET.Sdk.Publish.Tasks.dll"/>
  <PropertyGroup>
    <TransformSource>Web.config</TransformSource>
    <Transformer>Web.Live.config</Transformer>
    <Destination>Output.Web.config</Destination>
  </PropertyGroup>
  <Target Name="TransformConfig">
    <Message Text="From TransformSource : $(TransformSource)" />
    <Message Text="Using Transform : $(Transformer)" />
    <Message Text="Output : $(Destination)" />
    <Message Text="MSBuildSDKsPath=$(MSBuildSDKsPath)" Condition="'$(MSBuildSDKsPath)' != ''" />
    <TransformXml Source="$(TransformSource)" Transform="$(Transformer)" Destination="$(Destination)"/>
  </Target>
</Project>

which you can run with just msbuild or supply parameters with

msbuild /p:TransformSource=... /p:Transformer=...



回答3:


Microsoft has posted XDT to codeplex http://xdt.codeplex.com and as a NuGet package https://www.nuget.org/packages/Microsoft.Web.Xdt/. I have also created a NuGet pig with an MSBuild task, TransformXml, and an .exe to invoke them https://www.nuget.org/packages/SlowCheetah.Xdt/1.1.6-beta.

For PowerShell I've created a self-bootstrapping script which you can use https://gist.github.com/sayedihashimi/f1fdc4bfba74d398ec5b.

More about self bootstrapping scripts at http://sedodream.com/2014/07/22/StopCheckinginBinariesInsteadCreateSelfbootstrappingScripts.aspx.




回答4:


Based on Michel's answer I wrote a C# function that will accomplish the same.

Of course you could invoke the resultant DLL with PowerShell, but I was actually looking for a fully programatic version, so here it is, in case anybody else is looking for similar solution:

using Microsoft.Web.XmlTransform;

...

public static void TransformConfig(string configFileName, string transformFileName)
{
     var document = new XmlTransformableDocument();
     document.PreserveWhitespace = true;
     document.Load(configFileName);

     var transformation = new XmlTransformation(transformFileName);
     if (!transformation.Apply(document))
     {
         throw new Exception("Transformation Failed");
     }
     document.Save(configFileName);
}

You will just need to include reference to following:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.XmlTransform.dll




回答5:


I updated the script a bit to make it work with the latest version of powershell and make it a bit easier.

function XmlDocTransform($xml, $xdt)
{
      $scriptpath = $PSScriptRoot + "\"
      $xmlpath = $scriptpath + $xml
      $xdtpath = $scriptpath + $xdt

      if (!($xmlpath) -or !(Test-Path -path ($xmlpath) -PathType Leaf)) {
         throw "Base file not found. $xmlpath";
      }

      if (!($xdtpath) -or !(Test-Path -path ($xdtpath) -PathType Leaf)) {
         throw "Transform file not found. $xdtpath";
      }

      Add-Type -LiteralPath "$PSScriptRoot\Microsoft.Web.XmlTransform.dll"

      $xmldoc = New-Object   Microsoft.Web.XmlTransform.XmlTransformableDocument;
      $xmldoc.PreserveWhitespace = $true
      $xmldoc.Load($xmlpath);

      $transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdtpath);
      if ($transf.Apply($xmldoc) -eq $false)
      {
          throw "Transformation failed."
      }
      $xmldoc.Save($xmlpath);

      Write-Host "Transformation succeeded" -ForegroundColor Green
  }

And to invoke the function use

 XmlDocTransform "App.config" "App.acc.config"



回答6:


Take a looked at using MSDeploy since it has PowerShell scripting APIs that allow you to transform and deploy your package.

You can also look at XML-Document-Transform which if you wanted to you can write your own code to perform the Transform.

Here is a codeplex project that did something similar.XDT Transformation Tool




回答7:


So extended slightly to work recursively

    function XmlDocTransform($xml, $xdt)
    {
        if (!$xml -or !(Test-Path -path $xml -PathType Leaf)) {
            throw "File not found. $xml";
        }
        if (!$xdt -or !(Test-Path -path $xdt -PathType Leaf)) {
            throw "File not found. $xdt";
        }
        $scriptPath = (Get-Variable MyInvocation -Scope 1).Value.InvocationName | split-path -parent
        Add-Type -LiteralPath "$scriptPath\Microsoft.Web.XmlTransform.dll"
        $xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
        $xmldoc.PreserveWhitespace = $true
        $xmldoc.Load($xml);
        $transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdt);
        if ($transf.Apply($xmldoc) -eq $false)
        {
            throw "Transformation failed."
        }
        $xmldoc.Save($xml);
    }
    function DoConfigTransform($webFolder, $environment)
    {
        $allConfigFiles = Get-ChildItem $webFolder -File -Filter *.config -Recurse
          $transformFiles = $allConfigFiles | Where-Object {$_.Name -like ("*." + $environment + ".config")} | %{$_.fullname}
          ForEach($item in $transformFiles)
          {
            $origFile = $item -replace("$environment.",'')
              XmlDocTransform -xml $origFile -xdt $origFile$item
              #Write-Output ("orig = " + $origFile + ", transform = " + $item)
          }
          cd C:\WebApplications\xxx\xxx\xxx\
          .\PostDeploy.ps1
    }
    DoConfigTransform -webFolder "C:\WebApplications\xxx\xxx\xxx" -environment "xx-xxx-xx"

So the DoConfigTransform logic goes:

  • Find all config files recursively
  • Find all transform templates for the environment we are in #passed in as a parameter
  • For each transform file, find the corresponding config
  • Then do transform
  • Code runs a postdeploy script to remove all unwanted transform files.


来源:https://stackoverflow.com/questions/8989737/web-config-transforms-outside-of-microsoft-msbuild

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!