Pregunta

¿Puedo utilizar el mecanismo de las transformaciones de configuración de MSDeploy para transformar otros archivos?

¿Fue útil?

Solución

(otro enfoque)

El embalaje MSDeploy se invoca jsut durante una ejecución MSBUILD para su proyecto.

TransformXml es una tarea incluida de un .csproj o .vsproj construcción.

Sólo modificar su proceso de construcción de invocar esa tarea en cualquier archivo que necesita.

Por ejemplo, lo que hacemos es escribir un objetivo de encargo

<Target Name="TransformFile">

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

A continuación, modificar su .csproj para ejecutar esta tarea antes del Publish se invoca.

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

Otros consejos

La respuesta de Taylor no funcionó para mí y que no dio más detalles. Así que fui espeleología en los Microsoft.Web.Publishing.targets archivo para encontrar una solución. La siguiente Target MSBuild se puede añadir al archivo de proyecto para transformar todos los demás archivos de configuración en el directorio raíz de la aplicación. Disfrutar:)

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

Respuesta corta: Sí se puede. Pero es difícil".

Respuesta larga: Cuando hacemos uso de los sitios a los destinos tuvimos la web.test.config habitual, y web.prod.config. Esto funcionó bien hasta que introdujimos log4net.test.config y log4net.prod.config. MSBuild no pasará automáticamente a través y reemplazar todos estos. Sólo lo hará los web.config.

Si desea que la auténtica pétreas ir al último fragmento de código. Muestra las funciones para tomar una configuración y reemplazarlo con un reemplazo. Pero ... que tendrá más sentido si describo todo el proceso.

El proceso:

  1. MSBUILD hace un paquete de archivos zip del sitio.
  2. Nos escribió una aplicación .NET a medida que se llevará a ese archivo zip y hacer los reemplazos de configuración en cada uno de los archivos. Vuelva a guardar el archivo zip.
  3. Ejecutar la orden MSDeploy para desplegar el archivo empaquetado.

MSBUILD no reemplazará automáticamente todas las configuraciones adicionales. Lo que es interesante es MSBuild eliminará cualquier configuraciones "extra". Por lo que su log4net.test.config habrá desaparecido después de la acumulación. Así que lo primero que tiene que hacer es msdbuild diga que mantenga esos archivos adicionales en su lugar.

Tiene que modificar su archivo vbproj para incluir un nuevo ajuste:

<AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings>

Abra el archivo de vbproj para la aplicación web en su editor de texto favorito. Vaya a cada configuración de despliegue que desea que esto se aplica también (liberación, prod, depuración, etc.) y añadir que la configuración en ella. Aquí está un ejemplo de nuestra configuración de "liberación".

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

Así que ahora msbduild realizará el proyecto, y mantener esos archivos extra en su lugar y no hacer los reemplazos. Ahora usted tiene que hacer manualmente.

escribió una aplicación .NET que estarán atentos a estos nuevos archivos zip. Escribí un código que hará girar a través de todo el paquete postal y encontrar configuraciones que coinciden con el configname {}. {Entorno} .config. Se extraerá ellos, reemplazarlos, y ponerlos de nuevo. Para hacer efectiva la sustitución utilizamos MSDeploy que los usos de la misma DLL. También uso Ionic.Zip hacer las cosas postal.

Así que añadir una referencia a:

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

Importar:

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

Este es el código que hace girar a través del archivo 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

Por último es el más importante, pero donde realmente hacemos la sustitución de los 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

Como he dicho ... es difícil, pero se puede hacer.

Sólo para añadir a esta awnser, con el fin de modificar otros archivos que el web.config en una aplicación publicada con MSDeploy (webdeploy) se puede establecer el atributo scope en el archivo parameters.xml en la raíz del proyecto:

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

scope es una expresión regular que será utilizado para encontrar archivos para aplicar el XPath match a. No he experimentado con esto extensamente pero por lo que entiendo que simplemente reemplaza lo que cada vez los partidos XPath con el valor que se proporciona más adelante.

También hay otros valores que se pueden utilizar para kind que tienen diferentes comportamientos de un XPath, consulte https://technet.microsoft.com/en-us/library/dd569084 (v = ws.10) .aspx para más detalles

Nota: esto se aplica a cuando se está utilizando un parameters.xml, no cuando se utiliza el web.config.Debug / ficheros Release

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top