How to transform log4net config like web.config?

2019-03-11 10:15发布

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.

6条回答
混吃等死
2楼-- · 2019-03-11 10:31

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>
查看更多
甜甜的少女心
3楼-- · 2019-03-11 10:34

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.

查看更多
女痞
4楼-- · 2019-03-11 10:34

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> 
查看更多
女痞
5楼-- · 2019-03-11 10:45
时光不老,我们不散
6楼-- · 2019-03-11 10:53

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.

查看更多
Root(大扎)
7楼-- · 2019-03-11 10:55

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)

查看更多
登录 后发表回答