Могу ли я использовать механизм преобразования конфигурации MSDeploy для преобразования других файлов?
Преобразование файлов с помощью msdeploy
Ответы (4)
(другой подход)
Пакет 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'" />
Ответ Тейлора мне не помог, и он не предоставил дополнительных подробностей. Поэтому я начал копаться в файле 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>
Короткий ответ: Да, можете. Но это "сложно".
Длинный ответ: когда мы развертываем сайты в местах назначения, у нас есть обычные файлы web.test.config и web.prod.config. Это работало нормально, пока мы не представили log4net.test.config и log4net.prod.config. MSBuild не будет автоматически проходить и заменять все это. Он будет делать только файлы web.config.
Если вы хотите подробностей, перейдите к последнему фрагменту кода. Там показаны функции взять один конфиг и заменить его заменой. Но... будет понятнее, если я опишу весь процесс.
Процесс:
- Msbuild создает zip-архив сайта.
- Мы написали специальное приложение .net, которое возьмет этот zip-файл и заменит конфигурацию в каждом из файлов. Пересохраните zip-файл.
- Выполните команду msdeploy, чтобы развернуть упакованный файл.
MSbuild не заменит автоматически все дополнительные конфигурации. Что интересно, MSBuild удалит любые «лишние» конфиги. Таким образом, ваш log4net.test.config исчезнет после сборки. Итак, первое, что вам нужно сделать, это указать msdbuild сохранить эти дополнительные файлы на месте.
Вы должны изменить свой файл vbProj, чтобы включить новый параметр:
<AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings>
Откройте файл 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. Он извлечет их, заменит и вернет обратно. Для фактической замены мы используем те же библиотеки DLL, что и MSDeploy. Я также использую Ionic.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.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
Как я уже сказал... это сложно, но это можно сделать.
Просто чтобы добавить к этому awnser, чтобы изменить другие файлы, кроме web.config в приложении, опубликованном с помощью msdeploy (webdeploy), вы можете установить атрибут scope
в файле parameters.xml в корне проекта:
<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