Transformer les fichiers avec msdeploy
Question
Puis-je utiliser la config de mécanisme transforme MSDeploy pour transformer d'autres fichiers?
La solution
(une autre approche)
L'emballage est msdeploy jsut invoqué lors d'une course MSBuild pour votre projet.
TransformXML est une tâche incluse d'un .csproj ou .vsproj construction.
Il suffit de modifier votre processus de construction d'invoquer cette tâche sur tout fichier dont vous avez besoin.
Par exemple, ce que nous faisons est d'écrire une cible personnalisée
<Target Name="TransformFile">
<TransformXml Source="$(DestinationPath)\$(Sourcefile)"
Transform="$(DestinationPath)\$(TransformFile)"
Destination="$(DestinationPath)\$(DestFile)" />
</Target>
Ensuite, modifiez votre .csproj pour exécuter cette AVANT est appelée la tâche de publication.
<CallTarget Targets="TransformFile"
Condition="'$(CustomTransforms)'=='true'" />
Autres conseils
La réponse par Taylor n'a pas fonctionné pour moi et il n'a pas fourni de plus amples détails. Je suis donc allé spéléo dans le fichier Microsoft.Web.Publishing.targets pour trouver une solution. Le Target
MSBuild suivant peut être ajouté au dossier de projet pour transformer tous les autres fichiers de configuration dans le répertoire racine de l'application. Enjoy:)
<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>
Réponse courte: Oui, vous pouvez. Mais il est « difficile ».
Réponse longue: Lorsque nous déployons des sites vers des destinations que nous avions l'habitude web.test.config et web.prod.config. Cela a bien fonctionné jusqu'à ce que nous avons introduit log4net.test.config et log4net.prod.config. MSBuild ne passe pas automatiquement par et remplacer toutes ces questions. Il ne le fera que les web.config.
Si vous voulez aller de Nitty Gritty au dernier extrait de code. Il montre les fonctions de prendre une config et le remplacer par un remplacement. Mais ... il aura plus de sens si je décris le processus.
Le processus:
- MSBuild fait un paquet de fichier zip du site.
- Nous avons écrit une coutume app .net qui prendra ce fichier zip et faire les remplacements de configuration sur chacun des fichiers. Réenregistrez le fichier zip.
- Exécuter la commande msdeploy pour déployer le fichier compressé.
MSBuild ne remplacera pas automatiquement toutes les configs supplémentaires. Ce qui est intéressant est MSBuild va supprimer les configs « supplémentaires ». Donc, votre log4net.test.config aura disparu après sa construction. Donc, la première chose que vous devez faire est de dire msdbuild de garder ces fichiers supplémentaires en place.
Vous devez modifier votre fichier vbProj pour inclure un nouveau paramètre:
<AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings>
Ouvrez votre fichier vbProj pour l'application Web dans votre éditeur de texte favori. Accédez à chaque configuration de déploiement que vous souhaitez que cela s'applique aussi (version, prod, debug, etc.) et d'ajouter que config en elle. Voici un exemple de configuration « 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>
Alors maintenant msbduild va construire le projet et de garder ces fichiers supplémentaires en place et ne pas faire les remplacements. Maintenant, vous devez les faire manuellement.
Nous avons écrit une application .net qui guetterez ces nouveaux fichiers zip. J'ai écrit un code qui tournera à travers l'ensemble du paquet zip et trouver des configs qui correspondent à la {configname}. {Env} .config. Il les extraire, les remplacer, et les remettre. Pour ce faire, le remplacement réel que nous utilisons les utilisations MSDeploy de la même DLL. Je l'utilise aussi Ionic.Zip pour faire les choses zip.
ajouter une référence à:
Microsoft.Build.dll
Microsoft.Build.Engine.dll
Microsoft.Web.Publishing.Tasks (possibly, not sure if you need this or not)
Importer:
Imports System.IO
Imports System.Text.RegularExpressions
Imports Microsoft.Build.BuildEngine
Imports Microsoft.Build
Voici le code qui tourne à travers le fichier 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
Enfin, mais le plus important est que nous faisons en fait le remplacement des 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
Comme je l'ai dit ... il est difficile, mais il peut être fait.
Juste pour ajouter à cette awnser, afin de modifier d'autres fichiers que le web.config dans une application publiée msdeploy (webdeploy), vous pouvez définir l'attribut scope
dans le fichier parameters.xml à la racine du projet:
<parameters>
<parameter name="MyAppSetting" defaultvalue="_defaultValue_">
<parameterentry match="/configuration/appSettings/add[@key='MyAppSetting']/@value" scope=".exe.config$" kind="XmlFile">
</parameterentry>
</parameter>
</parameters>
scope
est une expression régulière qui sera utilisé pour trouver des fichiers pour appliquer le match
XPath à. Je nai expérimenté avec ce largement, mais pour autant que je comprends qu'il remplace simplement ce que jamais les matchs de XPath avec la valeur fournie plus tard.
Il y a aussi d'autres valeurs qui peuvent être utilisées pour kind
qui ont des comportements différents d'une XPath, voir https://technet.microsoft.com/en-us/library/dd569084 (v = ws.10) .aspx pour plus de détails
Note: cela vaut quand vous utilisez un parameters.xml, pas lorsque vous utilisez le web.config.Debug / fichiers Release