I have a web project (ASP.NET MVC 4 project) that has a number of configurations stored in Web.Config and in NLog.config files.
I have
I also had this issue but in an ASP.NET MVC 5 project. I do not have any AfterBuild
events only added one line in the csproj file in the tag for the NLog.config file:
<TransformOnBuild>true</TransformOnBuild>
It looks like this tells the msbuild.exe to do the transformation upon build.
My setup is two files NLog.Debug.config
and NLog.Release.config
used for transformations based on build configuration (/p:Configuration="Release"
).
<Content Include="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TransformOnBuild>true</TransformOnBuild>
</Content>
<None Include="NLog.Debug.config">
<DependentUpon>NLog.config</DependentUpon>
<IsTransformFile>True</IsTransformFile>
</None>
<None Include="NLog.Release.config">
<DependentUpon>NLog.config</DependentUpon>
<IsTransformFile>True</IsTransformFile>
</None>
I have been using both build time web.config
transformation with SlowCheetah NuGet package and built-in deployment time transformation. For NLog.config
files I have NLog.*.config
files for each build environment. Previously each of those files had full NLog.config
contents, and had a task in deployment to overwrite NLog.config
with a specific NLog.*.config
and delete all NLog.*.config
afterwards.
Decided today to have these files to be transformable instead, similar to the way web.config
is generated from web.template.config
and web.template.*.config
(with the help of ProjectName.wpp.targets
file), but not replacing NLog.config
at build time (don't want to have servers' log file paths in my localhost runs).
Here's how I've got it working - in ProjectName.wpp.targets
file I've used OnAfterCopyAllFilesToSingleFolderForPackage
"event" to transform NLog.config
file into the temporary intermediate directory (which is subsequently used for publishing). This is the full ProjectName.wpp.targets
file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Make sure Web.config will be there even for package/publish -->
<Target Name="CopyWebTemplateConfig" BeforeTargets="PrepareForBuild">
<Copy SourceFiles="Web.template.config"
DestinationFiles="Web.config"/>
</Target>
<PropertyGroup>
<PrepareForRunDependsOn>
$(PrepareForRunDependsOn);
UpdateWebConfigBeforeRun;
</PrepareForRunDependsOn>
</PropertyGroup>
<PropertyGroup>
<OnAfterCopyAllFilesToSingleFolderForPackage>
$(OnAfterCopyAllFilesToSingleFolderForPackage);
UpdateNLogConfigBeforePublish;
</OnAfterCopyAllFilesToSingleFolderForPackage>
</PropertyGroup>
<!-- This target will run right before you run your app in Visual Studio -->
<Target Name="UpdateWebConfigBeforeRun">
<Message Text="Configuration: $(Configuration): Web.template.$(Configuration).config"/>
<TransformXml Source="Web.template.config"
Transform="Web.template.$(Configuration).config"
Destination="Web.config" />
</Target>
<Target Name="UpdateNLogConfigBeforePublish">
<Message Text="Configuration: $(Configuration): NLog.$(Configuration).config"/>
<TransformXml Source="NLog.config"
Transform="NLog.$(Configuration).config"
Destination="$(IntermediateOutputPath)\Package\PackageTmp\NLog.config" />
</Target>
<!-- Exclude the config template files from the created package -->
<Target Name="ExcludeCustomConfigTransformFiles" BeforeTargets="ExcludeFilesFromPackage">
<ItemGroup>
<ExcludeFromPackageFiles Include="Web.template.config;Web.template.*.config"/>
<ExcludeFromPackageFiles Include="NLog.*.config"/>
</ItemGroup>
<Message Text="ExcludeFromPackageFiles: @(ExcludeFromPackageFiles)" Importance="high"/>
</Target>
</Project>
The NLog.*.config
files then use the standard transformations, e.g.:
<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"
internalLogFile="c:\temp\ProjectName.ENV.nlog.txt"
xdt:Transform="SetAttributes(internalLogFile)">
<variable name="envName" value="ENV"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
<targets>
<target name="exceptionsMail" to="ENV.email@some.email.domain"
xdt:Transform="SetAttributes(to)" xdt:Locator="Match(name)" />
</targets>
<rules>
<logger name="Exceptions" minlevel="Error" writeTo="exceptionsMail"
xdt:Transform="Insert" />
</rules>
</nlog>
I've managed it without moving all configuration into web.config or app.config. (There is nothing, connected with nlog in web/app.config at all).
1) Using this article: applying msbuild config transformations to any config file I've created all transformations, which are necessary and added transformation task.
2)Then I've checked if there are any other tasks, which do similar things. In my case there was one, which had been created by SlowCheetah(VS extension to automatically add transformations). I've removed it - and everything became ok. (SlowCheetah can restore its settings on next build, so it is better to remove it or suppress its transformation task)
3) My transform files look like this one:
<?xml version="1.0"?>
<!-- For more information on using app.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns="http://www.nlog-project.org/schemas/NLog.xsd">
<targets>
<target xsi:type="Database" name="DbLogging"
connectionString=".\SQLEXPRESS;Initial Catalog=xxxxx;User ID=xxxx;Pwd=xxxx;" xdt:Transform="SetAttributes(connectionString)" xdt:Locator="Match(name)">
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="DbLogging" />
<logger name="Namespace.*" minlevel="Debug" writeTo="DbLogging" xdt:Transform="SetAttributes(writeTo)" xdt:Locator="Match(name)" />
</rules>
</nlog>
I got this working by, in transformation config, include the xmlns:xsi namespace definied in web.config for the nlog section.
<nlog xmlns:xsi="...">
<variable name="..." value="..." xdt:Transform="Replace" xdt:Locator="Match(name)" />
</nlog>