Set ApplicationData folder on app.config and get it on Nlog.config - c#

I'd like to set the path of NLog log file on app.config.
I know how to set the applicationData folder on NLog.config. It's like that:
<target xsi:type="File"
name="logFileCsv"
fileName="${specialfolder:folder=ApplicationData}/something/something.log">
And if I use the NLog.Extended I know how to get key values from app.config and use them on NLog.config, like that:
<target xsi:type="File" name="logFileCsv" fileName="${appsetting:name=LogPath">
And on app.config should be like this
<add key="LogPath" value="${APPDATA}/something/something.log" />
But it's not working the way I want. NLog is creating the log file on c:\..\${APPDATA}/something/something.log"
So, I'd like to know how to set the ApplicationData folder on app.config to be understandable by NLog?

Unfortunately the ${appsetting} won't evaluate the value.
As work around you can do:
<target fileName="${APPDATA}/${appsetting:name=LogPath}" />
note: wrapping in a ${replace} also won't work

I tried the answer of Julian, but it wasn't utterly successful:
Error FileTarget(Name=logFileCsv): Failed write to file '\\something\something.log
However, with that help and workaround, I figure out how to do it:
So in App.config just add the final path:
<add key="LogPath" value="\something\something.log"/>
and in NLog.Config I did this:
<target xsi:type="File" name="logFileCsv" fileName="${specialfolder:folder=ApplicationData}/${appsetting:name=LogPath}">
And now the log is written on the right path: C:\Users\user\AppData\Roaming\something\something.log

Related

NLog - Can a FallbackGroup wrapper contain another FallbackGroup wrapper?

In NLog ... can a FallbackGroup wrapper contain another FallbackGroup wrapper? That is I want a cascade effect to handle if my 1st target (writing to a Database) fails, then my 2nd target will be to write to both a file and send an email.
And what config settings are needed to implement this structure (so that NLog handles encountered exceptions [ex. writing to the database failure] properly)?
Thanks for your time and any suggestions you offer.
If you want fallback to write to two targets then you can combine it with SplitGroup:
<target xsi:type="FallbackGroup"
name="db_fallback"
returnToFirstOnSuccess="true">
<target xsi:type="Database" name="db" />
<target xsi:type="SplitGroup" name="split_db_fallback">
<target xsi:type="file" name="file_db_fallback" />
<target xsi:type="mail" name="mail_db_fallback" />
</target>
</target>
See also https://github.com/nlog/nlog/wiki/SplitGroup-target

How to make Web.Config Transform files work during both build & publish? [duplicate]

How can I merge and make use of Web.debug.config in visual studio 2010 built-in debugger?
This is a known bug. That feature can be used right now only as part of the deploy process.
https://connect.microsoft.com/VisualStudio/feedback/details/523221/have-web-debug-config-apply-during-development
Please upvote it, if you encounter this too, so this will be fixed ASAP.
This is actually quite simple to do and, believe it or not, it seems this is the way VS is designed to work.
Add the following lines verbatim right before the closing "Project" tag of the .csproj file of the project that contains web.config.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="Transform">
<MakeDir Directories="obj\$(Configuration)" Condition="!Exists('obj\$(Configuration)')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="obj\$(Configuration)\Web.config" StackTrace="true" />
</Target>
Put the following lines verbatim to the post-build event in the project properties of the project that contains the web.config file. Do this for each build configuration you want the transformations to run for.
"$(MSBUILDBINPATH)\msbuild" "$(ProjectPath)" /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
xcopy "$(ProjectDir)obj\$(ConfigurationName)\Web.Config" "$(ProjectDir)". /F /R /Y
I had solved this in a simpler way, by adding this at the end of the .csproj file, right before the tag. This is similar to keitn's answer, with the difference that it doesn't use a post build event.
<Target Name="BeforeBuild">
<TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>
I didn't want to update the web.config in my project just the one that ends up in the bin folder so here is how I did it.
Add the following to the end of .csproj (just before the final closing project tag)
<Target Name="Transform">
<MakeDir Directories="bin" Condition="!Exists('bin')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="bin\$(TargetFileName).config" StackTrace="true" />
</Target>
Then add the following post build step
"$(MSBUILDBINPATH)\msbuild" "$(ProjectPath)" /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
This means that when you build a transform takes place from the debug/release config to WebsiteName.Config file in the output bin directory thus not interfering with the main web.config in the project.
After reading many similar posts and having problems with files not being able to be overwritten or web.config not being accessible because it is read only this is what I got working for me:
<Target Name="BeforeBuild" Condition="$(Configuration) == 'MyAltDebugConfiguration'">
<ItemGroup>
<OriginalWebConfig Include="$(ProjectDir)Web.config"/>
<TempWebConfig Include="$(ProjectDir)TempWeb.config"/>
</ItemGroup>
<Exec Command=""$(DevEnvDir)tf.exe" checkout "$(ProjectDir)Web.config"" />
<Copy SourceFiles="#(OriginalWebConfig)" DestinationFiles="#(TempWebConfig)" />
<TransformXml Source="$(ProjectDir)TempWeb.config"
Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
Notes:
This runs as the BeforeBuild target.
I only want it to run under a certain configuration (an alternative debug environment) and so that is why I have the Condition. When deploying via web deploy the publishing target kicks in and I don't need this target to run.
I don't want to have to remember to check out web.config (only to undo it when I am done) so I check web.config out before beginning the transform. If you aren't using TFS you can remove this line.
Because VS (2010) \ msbuild doesn't want to let go of the Source web.config I use a temp file (thanks to this article for the info: http://www.diaryofaninja.com/blog/2011/09/14/using-custom-webconfig-transformations-in-msbuild)
I tried adding a command to delete the TempWeb.config but VS \ msbuild doesn't want to let go of it. I can live with it as it doesn't get added to TFS.
I know this is old, but I'm facing the same problem. We have Test, Staging, Live configs that replace endpoints, connection strings etc. from the default Web.config
However I would do the following:
Right click on the desired transform config (e.g. Web.Live.config)
Click on "Preview Transform"
Copy everything from right (it's how the Web.config looks with the transformation)
CTRL+A + CTRL+C
Open Web.config file (default one)
Select everything (CTRL+A) and paste it in (CTRL+V)
Run
It's not that many steps and is done pretty quickly when you get a hang of it. Hope this helps. :)
#ologesa:
Your solution needs write access to the original Web.config (you must check-out in TFS).
The better solution is to directly generate the Web.config in the bin folder like keitn does this. When we combine keitn's and your solution we get this one:
<Target Name="BeforeBuild">
<Message Text="Transforming Web.config from Web.$(Configuration).config" Importance="high" />
<MakeDir Directories="bin" Condition="!Exists('bin')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="bin\$(TargetFileName).config" StackTrace="true" />
</Target>

How to add config transformations for a custom config file in Visual Studio?

The project I am working on involves reading a lot of service endpoints (url) from a config file. Since the list would be quite large I decided to keep them in a custom config file to keep my web.config clean and small. I included the custom section to my web as below:
<mySection configSource="myConfig.config" />
I works perfectly fine.
But the problem of transformation appears during the deployment of the project to different environments. I have three web.config files:
Web.config
Web.Uat.config
Web.Release.config
While the transformation web.config works, the transformations for custom config files fails at deployment.
Is there an way I can transform the custom config file during deployment?
Visual Studio transforms only web.config files by default.
If you need custom config file with transformation for DEV, UAT, PROD, etc environments, then try to
Use custom extensions for Visual Studio like SlowCheetah - XML Transforms for Config transformation preview functionality.
Add for the project from Nuget SlowCheetah to provide build in transformation.
A little bit details:
Add VS Extension SlowCheetah from Extensions and Updates
Right click on your myconfig.config and choose add transorm:
Inside each defined configurations insert your own transormation rulles like that:
<services xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<service name="WebApplication1.Services.Service2" xdt:Transform="Replace" xdt:Locator="Match(name)" >
<endpoint address="http://localhost:57939/Services/DebugService" behaviorConfiguration="WebApplication1.Services.Service2AspNetAjaxBehavior"
binding="webHttpBinding" contract="WebApplication1.Services.Service2" />
</service>
</services>
Hope it was helpful
I'm going to extend on Andoni Ripoll Jarauta's answer a little.
We were faced with a similar problem. I wanted to pull the connection strings out of the web.config file to limit merge conflicts. I also wanted create a "release" config containing static information when publishing.
...simple enough. Create a custom config file, webdb.config, and update the web.config file.
Ex.
web.config
<connectionStrings configSource="WebDB.config"/>
wedbdb.config (xml version="1.0" is required for transformation)
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
</connectionStrings>
Next add transformation files for webdb.config
WebDB.Debug.config example:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings xdt:Transform="Replace" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add name="PRRADDataContainer" connectionString="metadata=~/PRRADData.csdl|~/PRRADData.ssdl|~/PRRADData.msl;provider=System.Data.SqlClient;provider connection string=';Data Source=localhost;Initial Catalog=;User ID=;Password=;multipleactiveresultsets=True;App=EntityFramework';" providerName="System.Data.EntityClient" />
<add name="MyConnectionString" connectionString="Data Source=localhost;Initial Catalog=;Persist Security Info=True;User ID=;Password=;" providerName="System.Data.SqlClient" />
</connectionStrings>
WebDB.Release.config example:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings xdt:Transform="Replace" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add name="PRRADDataContainer" connectionString="metadata=~/PRRADData.csdl|~/PRRADData.ssdl|~/PRRADData.msl;provider=System.Data.SqlClient;provider connection string=';Data Source=prod_server;Initial Catalog=;User ID=;Password=;multipleactiveresultsets=True;App=EntityFramework';" providerName="System.Data.EntityClient" />
<add name="MyConnectionString" connectionString="Data Source=prod_server;Initial Catalog=;Persist Security Info=True;User ID=;Password=;" providerName="System.Data.SqlClient" />
</connectionStrings>
Next we need to add an after-build event. This is created by simply editing the CSPROJ file.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<TransformXml Source="WebDB.config" Transform="WebDB.$(Configuration).config" Destination="WebDB.config" />
</Target>
Now when I run locally I'll get WebDB.Debug.config and when I publish my code I just need to make sure to select "Release" as the configuration source. In both cases the WebDB.config file will be updated with the corresponding file when you build.
NOTE: make sure you set the webdb.config, webdb.debug.config, and webdb.release.config to "Do not copy" for the "Copy to Output Directory" option.
Hope this helps!
I have been using SlowCheetah but I found something that I think is more elegant. Just telling to the build to generate the .config depending on the build configuration.
Having a app.Release.config in your project (or many more depending on you deployment needs) you just need to edit the project file (the .csproj one if you program in C#). Find the end of it, between the last </ItemGroup> and </Project> and add:
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<PropertyGroup>
<OutputTypeName>$(OutputType)</OutputTypeName>
<OutputTypeName Condition="'$(OutputTypeName)'=='Library'">dll</OutputTypeName>
<OutputTypeName Condition="'$(OutputTypeName)'=='Module'">dll</OutputTypeName>
<OutputTypeName Condition="'$(OutputTypeName)'=='Winexe'">exe</OutputTypeName>
</PropertyGroup>
<TransformXml Source="Config\app.config" Transform="Config\app.$(Configuration).config" Destination="$(OutputPath)\$(AssemblyName).$(OutputTypeName).config" />
</Target>
</Project>
Save and reload from VisualStudio. Compile in Release mode and check the bin/Release folder on your <MyProject>.config file the transformation is done.
This example applies to Exe and Dll files and any VisualStudio version because includes this post help
There is another approach that doesn't require installing extensions nor using build events.
Let's suppose you have your custom configs like so:
myConfig.config
myConfig.Uat.config
myConfig.Release.config
Then in your main Web.config you have this:
<mySection configSource="myConfig.config" />
Lastly, inside your Web.Uat.config you add a transform like this:
<mySection configSource="myConfig.Uat.config" xdt:Transform="SetAttributes" />
This is not transforming the myConfig.config file, but rather overriding the name of the custom config file that should be used. You can do the same for the Release and any other environments.
Your myConfig.Uat.config should not contain transformations, it should be a copy of the base custom config file, with the appropriate values for the custom environment.
The downside is everytime you add something to the base custom config file, you need to also add to the config files for other envs (even if the value should be the same through envs). So I'd consider just using these custom config files for settings that should be changed between envs.
I had a similar need to transform a custom config file, but in a class library. Andoni Ripoll Jarauta's solution worked when I built the project directly, but when I built another project that referenced it the transformed file would not get copied. I found that in addition I had to add the transformed file to AssignTargetPathsDependsOn for that to happen. This did the trick:
<PropertyGroup>
<AssignTargetPathsDependsOn>
$(AssignTargetPathsDependsOn);
BuildCustomConfig;
</AssignTargetPathsDependsOn>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="BuildCustomConfig">
<TransformXml Source="MyCustom.config" Transform="MyCustom.$(Configuration).config" Destination="$(OutputPath)\MyCustom.config" />
<ItemGroup>
<Content Include="$(OutputPath)\MyCustom.config" Condition="Exists('$(OutputPath)\MyCustom.config')">
<Link>MyCustom.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>
Since the OP asked about Web.config transformations during the deployment lets assume the WPP is already in there. So I've hacked on the WPP.
I use the following snippet to transform Umbraco's own config files (but indeed any configs suit well):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<UmbracoConfigsToTransform Include="Config\umbracoSettings.config">
<DestinationRelativePath>Config\umbracoSettings.config</DestinationRelativePath>
</UmbracoConfigsToTransform>
</ItemGroup>
<PropertyGroup>
<CollectWebConfigsToTransformDependsOn>
$(CollectWebConfigsToTransformDependsOn);
CollectUmbracoConfigsToTransform
</CollectWebConfigsToTransformDependsOn>
</PropertyGroup>
<Target Name="CollectUmbracoConfigsToTransform">
<!-- The logic comes from the 'CollectWebConfigsToTransform' task -->
<ItemGroup>
<WebConfigsToTransform Include="#(UmbracoConfigsToTransform)">
<Exclude>false</Exclude>
<TransformFile>$([System.String]::new($(WebPublishPipelineProjectDirectory)\$([System.IO.Path]::GetDirectoryName($([System.String]::new(%(DestinationRelativePath)))))).TrimEnd('\'))\%(Filename).$(Configuration)%(Extension)</TransformFile>
<TransformOriginalFolder>$(TransformWebConfigIntermediateLocation)\original</TransformOriginalFolder>
<TransformFileFolder>$(TransformWebConfigIntermediateLocation)\assist</TransformFileFolder>
<TransformOutputFile>$(TransformWebConfigIntermediateLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
<TransformScope>$([System.IO.Path]::GetFullPath($(WPPAllFilesInSingleFolder)\%(DestinationRelativePath)))</TransformScope>
</WebConfigsToTransform>
</ItemGroup>
</Target>
</Project>
I name it Umbraco.wpp.targets and drop inside project's root. Then the WPP automatically imports it.
All you have then to do is add a transform file (Config\umbracoSettings.Release.config in case of this sample).

XAML access user directory [duplicate]

My NLog targets is like this:
<targets>
<target xsi:type="Console" name="console"
layout="${longdate}|${level}|${message}" />
<target xsi:type="File" name="ErrorLog" fileName="${basedir}/error.txt"
layout="${longdate}
Trace: ${stacktrace}
${message}" />
<target xsi:type="File" name="AccessLog" fileName="${basedir}/access.txt"
layout="${shortdate} | ${message}" />
</targets>
But this causes problems if the user isn't an admin on their machine, because they will not have write access to "Program Files". How can I get something like %AppData% to NLog instead of BaseDir?
You're looking for the NLog special folders.
Example:
...fileName="${specialfolder:folder=ApplicationData}/Program/file.txt"...
Oren's answer should be the right answer. However, for the life of me I couldn't get it to work with my .NET 4.0 website using nLog 2.0.0.0. I ended up using simply
fileName="${basedir}app_data\logs\${shortdate}.log"
${specialfolder:ApplicationData} also works
The previous answers helped solve the problem I was having, but a couple of years later and the solution is now somewhat different under v4.3. The directory and filename are combined with the path.
#theGecko's link is still current for the syntax, but the page is deficient of an example:
https://github.com/nlog/NLog/wiki/Special-Folder-Layout-Renderer
The following example would write the file myLog.log to the current users application data roaming directory C:\USers\current.user\AppData\Roaming\My\Path\Somewhere:
fileName="${specialfolder:dir=My/Path/Somewhere/:file=myFile.log:folder=ApplicationData}"
For logging to the project directory:
While the previous answers work for the original question, searching for how to log to the project APP_DATA directory leads to this question. And while bkaid's answer works for ASP.NET and for using the APP_DATA folder specifically, for .NET Core and .NET 5 the solution is a bit different, because that motif has been abandoned in favor of defining a wwwroot folder for only those things which should be served, and the remainder being private. The answer for .NET Core/5, then, is to write to the solution root directory:
First, ensure the NLog.Web.AspNetCore assembly is added to nlog.config:
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
Then use one of the layout renderers provided by that extension, in this case ${aspnet-appbasepath} which references the solution root directory:
<targets>
<target name="file"
type="File"
xsi:type="File"
fileName="${aspnet-appbasepath}/log/${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}"/>
</targets>
This will write the file to <solution folder>/log/2021-07-01.log, which will never be served by the public-facing website. Other layout renderers provided by this assembly are listed on the NLog website.

Couldn't find solution file (CCNet & NAnt)

I am trying to configure CCNet to build my project.
I get the error:
Couldn't find solution file 'C:\CRUISECONTROL\BuildEngine\BuildEngine.sln'
I haven't specified that specific path so I assume it is using part of the build file path.
When I specify:
<buildArgs>-buildfile:C:\CRUISECONTROL\BuildEngine\BuildEngine.build -D:sln=C:\CRUISECONTROL\BuildEngine.sln</buildArgs>
Where it actually is, I get an error about file format which is expected.
How on earth do I specify the path to the file, at the moment I can only specify the file name.
Folder Layout:
C:\CRUISECONTROL\ **SOLUTION IS HERE**
C:\CRUISECONTROL\BuildEngine\ ** BUILD FILE IS HERE **
CCNet Config:
<tasks>
<nant>
<executable>C:\Program Files (x86)\NAnt\bin\NAnt.exe</executable>
<baseDirectory>C:\CRUISECONTROL</baseDirectory>
<buildArgs>-buildfile:C:\CRUISECONTROL\BuildEngine\BuildEngine.build -D:sln=BuildEngine.sln</buildArgs>
<nologo>false</nologo>
<targetList>
<target>build</target>
</targetList>
<buildTimeoutSeconds>1200</buildTimeoutSeconds>
</nant>
</tasks>
NAnt build file:
<?xml version="1.0"?>
<project name="BuildEngine" default="build" basedir=".">
<description>Build Engine Build File</description>
<property name="sln" value="sln.file.empty" overwrite="false" />
<target name="clean">
</target>
<target name="build" depends="clean">
<solution configuration="debug" solutionfile="${sln}" />
</target>
</project>
Thanks.
The build file is set in its own element within the nant element. See below.
<nant>
<executable>c:\nantdir\nant.exe</executable>
<buildArgs>-D:blah_prop=foobar</buildArgs>
<nologo>false</nologo>
<buildFile>default.build</buildFile>
<targetList>
<target>the-nant-target</target>
</targetList>
<buildTimeoutSeconds>9000</buildTimeoutSeconds>
</nant>
buildArgs are just properties to send to Nant. They have nothing to do with the nant file you're trying to use.
NAnt Documentation:
<Solution>
Right now, only Microsoft Visual Studio .NET 2002 and 2003 solutions and projects are supported.
Two hours wasted.

Categories