使用msdeploy转换文件

4
我可以使用MSDeploy的配置转换机制来转换其他文件吗?
4个回答

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'" />

你能提供一些如何设置 DestinationPath、Sourcefile、TransformFile 和 DestFile 的示例吗?我似乎找不到正确的 MSBuild 属性来动态设置它们。 - chief7
如果你只是将目标名称设置为"AfterBuild",那么它就会自动运行,而且你不需要使用"CallTarget"(至少在某些VS2012项目中)。 - nateirvin

4

Taylor的答案对我没用,而且他也没有提供更多细节。因此,我深入研究了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>

2

简短回答:是的,你可以。但这很“困难”。

详细回答: 当我们将网站部署到目标位置时,我们通常有web.test.config和web.prod.config。这个方法一直运行得很好,直到我们引入了log4net.test.config和log4net.prod.config。MSBuild不会自动替换所有这些配置文件,它只会替换web.config文件。

如果您想了解详细信息,请查看最后一个代码片段。它显示了将一个配置文件替换为另一个的函数。但是...如果我描述整个过程,那么它会更加清晰。

过程:

  1. Msbuild创建一个站点的zip文件包。
  2. 我们编写了一个自定义的.NET应用程序,它将获取该zip文件并对每个文件进行配置替换。重新保存zip文件。
  3. 执行msdeploy命令以部署打包文件。

MSBuild不会自动替换所有额外的配置文件。有趣的是,MSBuild将删除任何“额外”的配置文件。因此,构建后,你的log4net.test.config将被删除。所以你必须告诉msdbuild保留这些额外的文件。

你必须修改你的vbProj文件,包含一个新的设置:

<AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings>

打开你的vbProj文件,进入你喜欢的文本编辑器。导航到你想要应用的每个部署配置(release、prod、debug等),并将该配置添加到其中。这是我们“release”配置的一个示例。

<?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>

现在msbuild将构建项目并保留这些额外的文件,不进行替换。现在您需要手动完成它们。
我们编写了一个.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 

这是遍历zip文件的代码

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.config替换的位置。
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

就像我说的一样……虽然有点难,但是可以做到。


很棒/全面的回答,但你可以使用MsBuild来完成所有这些操作。请看我的回复。如果“额外”的文件是一个问题,你只需要修改包含传输到发布/打包命令的输入/输出文件的ItemGroups即可。 - Taylor Bird
是的,好主意。但在我的情况下唯一的问题是我们有15个站点都在做同样的事情,但配置不同等。所以我建立了这个来在部署时只是“做它”。不过你的方法更简单。 - Paul Lemke
完全忘记了这个的主要原因...它给我一个包,里面包含了每个环境的配置。所以我可以将完全相同的包部署到开发、测试、QA、阶段、生产等环境中。 - Paul Lemke
是的,我们仍然使用 msbuild 的概念来做相同的事情(一个包)。我们将所有配置文件转换并放入包中,然后推送该包。然后我们使用 msdeploy 的排除运算符自动地在部署时推送正确的配置。这种方法非常可扩展,我们目前用于将近 65 个应用程序部署在多个数据中心和 Azure 的架上。一开始可能有些麻烦,但经过多年的发展,我很高兴我们只使用了 " jsut Msbuild"。 - Taylor Bird
你能否详细说明一下你是如何做到的?我很想看到更多的细节。谢谢! - Paul Lemke

1

补充一下,如果要修改使用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文件时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接