简体   繁体   中英

How to transform log4net config like web.config?

From my .csproj file:

<Content Include="log4net.config">
  <SubType>Designer</SubType>
</Content>
<Content Include="log4net.Release.config">
  <DependentUpon>log4net.config</DependentUpon>
</Content>
<Content Include="log4net.Debug.config">
  <DependentUpon>log4net.config</DependentUpon>
</Content>
<Content Include="log4net.Live.config">
  <DependentUpon>log4net.config</DependentUpon>   
</Content>
<Content Include="log4net.Demo.config">
  <DependentUpon>log4net.config</DependentUpon>   
</Content>  

At the bottom of my .csproj file:

  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
    <Target Name="AfterCompile" Condition="exists('log4net.$(Configuration).config')">
      <TransformXml Source="log4net.config"
        Destination="$(IntermediateOutputPath)$(TargetFileName).config"
        Transform="log4net.$(Configuration).config" />
      <ItemGroup>
        <AppConfigWithTargetPath Remove="log4net.config"/>
        <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
          <TargetPath>$(TargetFileName).config</TargetPath>
        </AppConfigWithTargetPath>
      </ItemGroup>
    </Target>

From log4net.config

<connectionString name="ConnName" 
value="Data Source=localhost\sqlexpress;Initial Catalog=localdb;Persist Security Info=True;Integrated Security=SSPI;" />

From log4net.Live.config (removed sensitive data)

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionString name="ConnName" value="Data Source=127.0.0.1;Initial Catalog=DBName;Persist Security Info=True;User ID=userid;Password=pword"
        providerName="System.Data.SqlClient" xdt:Transform="Replace" xdt:Locator="Match(name)" />
</configuration>

I checked msbuild output and I see that it transformed my web.config correctly, but I see no output for it transforming log4net. Also, when I check the log4net.config file after publish, it has the original connection string.

What am I doing wrong :)?

Thanks!

Update

I had some errors in the code that msbuild were outputting as warnings that I didn't see. I fixed those and now I get some output from MSBuild:

AfterCompile: Transforming Source File: log4net.config Applying Transform File: log4net.Live.config Output File: obj\\Live\\Common.UI.Web.dll.config
Transformation succeeded

This is still a problem, because the file should be named log4net.config, not Common.UI.Web.dll.config...

For whatever reason

$(TargetFileName)

is taking on the name of the .csproj file name. If I replace it with just log4net, then it outputs correctly

Update

File is stuck in obj folder and is not getting picked up when publishing.

UPDATED: For Visual Studio 2012 (these updates work in VS2010 also)

After attempting many different solutions I dug into how web.Config transformations happen... Here is what I find the most elegant solution.

First off exclude your log4net.config files from your project, unless you truly understand the project XML you might end up with a very confusing duplicate reference. Do NOT delete the files just exclude them (we will be including them through the project editor).

Now unload your project and then edit it... or however you choose to get to the proj xml. Ensure that you have a node importing Microsoft.WebApplication.targets. If you are in a web project it might have been added for you... search for this node

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

Once you have this node you only need to add an ItemGroup node...

<ItemGroup>
  <WebConfigsToTransform Include="log4net.config">
    <DestinationRelativePath>log4net.config</DestinationRelativePath>
    <Exclude>False</Exclude>
    <TransformFileFolder>$(TransformWebConfigIntermediateLocation)\original</TransformFileFolder>
    <TransformFile>log4net.$(Configuration).config</TransformFile>
    <TransformOriginalFolder>$(TransformWebConfigIntermediateLocation)\original</TransformOriginalFolder>
    <TransformOriginalFile>$(TransformWebConfigIntermediateLocation)\original\%(DestinationRelativePath)</TransformOriginalFile>
    <TransformOutputFile>$(TransformWebConfigIntermediateLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
    <TransformScope>$(_PackageTempDir)\%(DestinationRelativePath)</TransformScope>
    <SubType>Designer</SubType>
  </WebConfigsToTransform>
  <None Include="log4net.Debug.config">
    <DependentUpon>log4net.config</DependentUpon>
  </None>
  <None Include="log4net.Release.config">
    <DependentUpon>log4net.config</DependentUpon>
  </None>
</ItemGroup>

I have included the dependent files with in the ItemGroup, although this is not necessary, but it keeps things together. Notice that you didn't create a new task or target, now the transformation is handled EXACTLY like the web.config transformations.

A Microsoft employee on his free time has added the ability to do this for all files now, like you could with web.config , in an extension called SlowCheetah. Check out the review SlowCheetah Xml Transform and the vsi extension download .

I have used the following article to do this type of configuration

http://geekswithblogs.net/EltonStoneman/archive/2010/08/20/using-msbuild-4.0-web.config-transformation-to-generate-any-config-file.aspx

it was most useful for me

Ended up using http://mint.litemedia.se/2010/01/29/transforming-an-app-config-file/ for both the app config and the log4net config. Works very nicely.

For the log4net config, add this to the csproj:

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Target Name="ApplyConfiguration" Condition="Exists('log4net.$(Configuration).config')">  
       <XslTransformation XmlInputPaths="log4net.config" XslInputPath="log4net.$(Configuration).config" OutputPaths="log4net.config_output" />  
       <Copy SourceFiles="log4net.config_output" DestinationFiles="log4net.config" />  
   </Target>  
   <Target Name="BeforeBuild">  
       <CallTarget Targets="ApplyConfiguration"/>  
   </Target> 

For me this solution worked best (VS2013):

  <Target Name="ApplyLoggingConfiguration" BeforeTargets="BeforeBuild" Condition="Exists('log4net.$(Configuration).config')">
    <TransformXml Source="log4net.config" Transform="log4net.$(Configuration).config" Destination="log4net.config" />
  </Target>

If you have other properties than $(Configuration) you are free to use what you need. We use publishprofiles and use this msbuild command in our CI build

msbuild ConfigTransform.sln /p:DeployOnBuild=true;PublishProfile=Test;Configuration=Release

in this case just replace $(Configuration) with $(PublishProfile)

ms007's answer nearly got me there though I was getting an access denied issue on the file as the build server had set it to read only. Here is my solution.

  <Target Name="ApplyLoggingConfiguration" BeforeTargets="BeforeBuild" Condition="Exists('log4net.$(Configuration).config')">

    <TransformXml Source="log4net.config"
                  Transform="log4net.$(Configuration).config"
                  Destination="temp_log4net.config" />
    <Copy SourceFiles="temp_log4net.config"
          DestinationFiles="log4net.config"
          OverwriteReadOnlyFiles="True" />

    <Delete Files="temp_log4net.config" />
  </Target>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM