Развернуть как один файл в .net5 с исключением log4net для файла конфигурации

Попытка развернуть консольное приложение, написанное на .Net 5, с помощью log4net в виде одного файла. Запуск развернутого приложения вызывает исключение.

Действия по воспроизведению

  • dotnet new console --name TestConsole --language C # (убедитесь, что .net 5.0)
  • Установочный пакет log4net
  • Program.cs
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure(new FileInfo("log.config"));
var logger = log4net.LogManager.GetLogger("TestLogger");
logger.Info("Hello World!");
}
  • log.config (всегда копировать)
<?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 - самодостаточный истинный -r win-x64

  • опубликовать (нет одного файла) = выдает исключение (при запуске консольного приложения)

dotnet publish -o. \ Publish --self -isted true -r win-x64 -p: PublishSingleFile = true

Выброшено исключение:

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)

Что я пропустил?


person McClint    schedule 20.11.2020    source источник


Ответы (1)


Поэтому я считаю, что проблема связана с изменением в .NET 5. Я также предполагаю, что log4net необходимо будет обновить для работы с новым форматом единого файла.

Здесь обсуждается, как .NET 5 обрабатывает отдельные файлы иначе, чем 3.1.

https://github.com/dotnet/core/issues/5409#issuecomment-715522029

В версии 3.1 технически единственный исполняемый файл распаковывается и запускается из временного хранилища (что могло вызвать проблемы с локальными ссылочными файлами, по крайней мере, по моему опыту, если эти файлы не были установлены в файле проекта для включения вне одного файла). В .NET 5 они пытались перейти к случаю, когда сборка оставалась в том же каталоге при выполнении в памяти. Однако очевидно, что это вызывает другие проблемы, которые вы обнаружили с log4net.

Эта ссылка выше дала мне ответ:

dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true

Параметр / p: IncludeAllContentForSelfExtract = true заставляет отдельные файлы .NET 5 действовать точно так же, как 3.1, и именно это сработало для меня.

Я буду продолжать попытки в течение следующих нескольких месяцев в надежде, что совместимость log4net .NET 5 начнет работать с новым форматом. Но, по крайней мере, этот флаг позволил мне двигаться дальше.

person Joshua Hudson    schedule 28.11.2020
comment
Это сработало, но файл log.config не был опубликован, мне пришлось скопировать его вручную. - person McClint; 03.12.2020
comment
@McClint, вам нужно отредактировать файл проекта и добавить эту строку для своего файла <ExcludeFromSingleFile>true</ExcludeFromSingleFile>, а также <CopyToOutputDirectory>Always</CopyToOutputDirectory> - person Rumplin; 06.01.2021
comment
добавление <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract> в мой файл * .pubxml в Visual Studio решило эту проблему. Спасибо за подсказку для IncludeAllContentForSelfExtract - person Rumplin; 08.03.2021