Trying to deploy a console-application written in .Net 5 with log4net as a single-file. Running deployed application throws exception.
Steps to reproduce
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure(new FileInfo("log.config"));
var logger = log4net.LogManager.GetLogger("TestLogger");
logger.Info("Hello World!");
}
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<logger name="TestLogger">
<level value="ALL" />
<appender-ref ref="console" />
</logger>
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level - %message%newline" />
</layout>
</appender>
</log4net>
dotnet publish -o .\Publish --self-contained true -r win-x64
dotnet publish -o .\Publish --self-contained true -r win-x64 -p:PublishSingleFile=true
excpetion thrown:
log4net:ERROR Exception while reading ConfigurationSettings. Check your .config file is well formed XML.
System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize
---> System.IO.FileNotFoundException: Cannot find file. (0x80070002)
at System.Reflection.RuntimeModule.GetFullyQualifiedName()
at System.Reflection.RuntimeModule.get_Name()
at System.Configuration.ClientConfigPaths..ctor(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigPaths.GetPaths(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigurationHost.get_ConfigPaths()
at System.Configuration.ClientConfigurationHost.GetStreamName(String configPath)
at System.Configuration.ClientConfigurationHost.get_IsAppConfigHttp()
at System.Configuration.Internal.DelegatingConfigHost.get_IsAppConfigHttp()
at System.Configuration.ClientConfigurationSystem..ctor()
at System.Configuration.ConfigurationManager.EnsureConfigurationSystem()
--- End of inner exception stack trace ---
at System.Configuration.ConfigurationManager.EnsureConfigurationSystem()
at System.Configuration.ConfigurationManager.PrepareConfigSystem()
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.get_AppSettings()
at log4net.Util.SystemInfo.GetAppSetting(String key)
log4net:ERROR Exception while reading ConfigurationSettings. Check your .config file is well formed XML.
System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize
---> System.IO.FileNotFoundException: Cannot find file. (0x80070002)
at System.Reflection.RuntimeModule.GetFullyQualifiedName()
at System.Reflection.RuntimeModule.get_Name()
at System.Configuration.ClientConfigPaths..ctor(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigPaths.GetPaths(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigurationHost.get_ConfigPaths()
at System.Configuration.ClientConfigurationHost.GetStreamName(String configPath)
at System.Configuration.ClientConfigurationHost.get_IsAppConfigHttp()
at System.Configuration.Internal.DelegatingConfigHost.get_IsAppConfigHttp()
at System.Configuration.ClientConfigurationSystem..ctor()
at System.Configuration.ConfigurationManager.EnsureConfigurationSystem()
--- End of inner exception stack trace ---
at System.Configuration.ConfigurationManager.PrepareConfigSystem()
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.get_AppSettings()
at log4net.Util.SystemInfo.GetAppSetting(String key)
What have I missed?
So I believe the issue is due to a change in .NET 5. I'm also assuming log4net will need to be updated to work with the new single file format.
There is a discussion here about how .NET 5 handles single files differently than 3.1.
https://github.com/dotnet/core/issues/5409#issuecomment-715522029
In 3.1, technically the single executable gets unzipped and ran from temp (which could cause issues with local referenced files as least in my experience, if those files were not set in the project file to be included outside the single file). In .NET 5 they were trying to move to a case where the assembly stayed in the same directory when executed into memory. However, clearly, this causes other issues as you found with log4net.
This link above put me on to the answer:
dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true
The /p:IncludeAllContentForSelfExtract=true forces .NET 5 single files to act exactly the same as 3.1 and is what worked for me.
I'll keep trying over the next few months with the hope that log4net .NET 5 compatibility starts working with the new format. But at least this flag let me move foward.
It worked but log.config did not get published, I hade to manually copy it.
@McClint you need to edit your project file, and add this line for your file
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
and also<CopyToOutputDirectory>Always</CopyToOutputDirectory>
adding
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
to my *.pubxml file in Visual Studio solved it for me. Thanks for the hint to IncludeAllContentForSelfExtract