سؤال

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 several publish profiles PublishProfile1, PublishProfile2 etc. When using a publish profile to deploy my web project to a server, I want to change a number of configs from both config files after deploy (some App Settings in Web.config and some values in NLog.config).

I have followed the steps from here and it works perfectly for changing the settings in Web.Config (e.g. the transformations from Web.PublishProfile1.Config are respected).

This is my NLog.PublishProfile1.Config transformation file:

<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">
  <nlog  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets >
      <target xsi:type="File"
              name="tracelog"
              fileName="NEW_VALUE_HERE" layout="${longdate} [${threadname}::${threadid}] ${pad:padding=5:inner=${level:uppercase=true}} ${logger} - ${message}"
              xdt:Transform="Replace"  xdt:Locator="Match(name)" />
    </targets>
  </nlog>
</nlog>

The problem is that I have the same transforms in NLog.PublishProfile1.config but these transformations are not applied after deploy as well.

Does anyone has a clue on why this transformation does not work for NLog.config but works ok for Web.config on a publish profile?

هل كانت مفيدة؟

المحلول

To solve this issue I had to:

1) Avoid the use of nlog.config

2) Create nlog section inside web.config and move the contents of nlog.config to web.config to be able the use the web.config transformation feature with one file. To further instructions please take a look at: NLog configuration instructions

3) Remove xmlns attributes from the nlog node. There seems to be a bug that messes everything during the web.config transformation. You can safely remove the following nodes:

xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4) I couldn't find a way to transform just a single target under nlog/targets node. To change the connection string of my logger, I had to copy the whole xml node, using a xdt:Transform="Replace" on the parent node like the following:

<nlog
      throwExceptions="true"
      internalLogLevel="Trace"
      internalLogFile="..\..\..\Logs\nlog-app.log" 
      xdt:Transform="Replace">
<!--(copy and paste all nlog configuration here)-->
</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>

It appears that I am quite late on this, but I have found that it is necessary for the NLog.config file to have the following:

<?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"
        xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd">
...
...
</nlog>

And the NLogTransform.config file (or whatever name it may have) to have the following:

<?xml version="1.0"?>
<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">
...
...
</nlog>

Here is some sample code to test the NLog transformation:

var tmpConfigFile = new FileInfo("C:\\NLogs\\NLog.config");
var transformFile = new FileInfo("C:\\Transforms\\NLogTransform.config");

if (transformFile.Exists) {
    var xmlTransformableDocument = new XmlTransformableDocument();
    xmlTransformableDocument.Load(tmpConfigFile.FullName);
    var xmlTransformation = new XmlTransformation(transformFile.FullName);
    xmlTransformation.Apply(xmlTransformableDocument);
    xmlTransformableDocument.Save(tmpConfigFile.FullName);
}

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>

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 ended up changing all of my publishing profiles (.pubxml files). I have added the following to my testing publishing profile as an example:

<Target Name="NLogTransform" AfterTargets="PipelineCopyAllFilesToOneFolderForMsdeploy">
<Message Text="NLog file transform according to NLog.WebDeploy - TEST.config" Importance="high" />
<TransformXml Source="NLog.config"
              Transform="NLog.WebDeploy - TEST.config"
              Destination="$(_PackageTempDir)\NLog.config" />
</Target>

Do notice though this only works for publishing profiles that make use of MsDeploy (aka web deploy). For publishing on a local folder use this target CopyAllFilesToSingleFolderForPackage.

The accepted answer did not work for me.

I wanted to have internal logging locally, but not on production. It turns out you need to include the namespace in the root configuration node.

What worked for me: web.config:

<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
  </configSections>

  <nlog autoReload="true" internalLogLevel="Trace" internalLogFile="internalLog.txt" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <!--nlog config stuff-->
  </nlog>
</configuration>

web.config.Release

<?xml version="1.0"?>
  <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns:nlg="http://www.nlog-project.org/schemas/NLog.xsd">
   <nlg:nlog xdt:Transform="RemoveAttributes(internalLogLevel,internalLogFile)" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">>
   </nlg:nlog>
  </configuration>

Found the solution here: https://www.jayway.com/2011/11/14/web-config-transformations-and-xml-namespaces/

Update - Adding a "key" attribute to the config and transformation files along with "Transform" and "Locator" attributes to the lines that change in the transformation file works in a standalone NLog.config file as follows:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      throwExceptions="false">
    <targets async="true">
      <target name="MyLogFile"
              xsi:type="File"
              keepFileOpen="false"
              fileName="C:/File/Logs/Example.${shortdate}.log"
              archiveFileName="C:/File/Logs/Example.${shortdate}.{#}.log"
              archiveEvery="Day"
              archiveNumbering="Rolling"
              maxArchiveFiles="30"
              layout="${Date:universalTime=false:format=o}, ${logger}, ${Level}, ${Message:jsonEncode=true} ${onexception:${newline}'Exception\: ${Exception:format=tostring:jsonEncode=true}', 'StackTrace\:${stacktrace:topFrames=12:jsonEncode=true}'}">
      </target>
    </targets>
    <rules>
        <logger key="logRule" name="*" minlevel="Trace" writeTo="MyLogFile" />
    </rules>
</nlog>

Transform file:

<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"
  xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  autoReload="true"
  throwExceptions="false">
  <rules>
    <logger key="logRule" name="*" minlevel="Info" writeTo="MyLogFile" xdt:Transform="Replace" xdt:Locator="Match(key)" />
  </rules>
</nlog>

Working example when nlog is in web.config - making maximal use of variables to minimise required transformations

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <variable name="SystemName" value="MyApp" />
    <variable name="LogPath" value="c:\log\${SystemName}" />
    <variable name="Layout" value="${longdate}|${level:upperCase=true}|t${threadid}|${logger}| ${message} ${exception:format=message,stacktrace}|${event-properties:item=ir-objects}" />

    <targets>
      <wrapper-target xsi:type="AsyncWrapper" name="file-info">
        <target xsi:type="File" createDirs="true" fileName="${LogPath}\${SystemName}.web.info.log" archiveAboveSize="31457280" archiveNumbering="Sequence" maxArchiveFiles="5" archiveEvery="Day" layout="${Layout}" />
      </wrapper-target>

    </targets>

    <rules>
      <logger name="*" minlevel="Info" writeTo="file-info" />
    </rules>
  </nlog>
</configuration>

Transform file:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xmlns:nlog="http://www.nlog-project.org/schemas/NLog.xsd">
  <nlog:nlog>
    <nlog:variable name="LogPath" value="D:\logs\uat\${SystemName}"  xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
  </nlog:nlog>
</configuration>

The trick is to namespace all the nlog elements - nlog, variable

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>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top