Вы правы, что код размещен не работает.Этот код использует файл конфигурации (FileConfigurationSource) в качестве метода настройки Enterprise Library.
Давайте углубимся глубже и посмотрим, будет ли работать программная конфигурация.
Мы будем использовать Fluent API, поскольку он является предпочтительным методом для программной конфигурации:
var builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.WithOptions
.DoNotRevertImpersonation()
.FilterEnableOrDisable("EnableOrDisable").Enable()
.LogToCategoryNamed("General")
.WithOptions.SetAsDefaultCategory()
.SendTo.FlatFile("FlatFile")
.ToFile(@"fluent.log");
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
var defaultWriter = new LogWriterFactory(configSource).Create();
defaultWriter.Write("Test1", "General");
var filter = defaultWriter.GetFilter<LogEnabledFilter>();
filter.Enabled = false;
defaultWriter.Write("Test2", "General");
Если вы попробуете этот код фильтр не будет обновляться - так очередной провал.
Давайте попробуем использовать «старую школу» программную конфигурацию с помощью классов непосредственно:
var flatFileTraceListener = new FlatFileTraceListener(
@"program.log",
"----------------------------------------",
"----------------------------------------"
);
LogEnabledFilter enabledFilter = new LogEnabledFilter("Logging Enabled Filter", true);
// Build Configuration
var config = new LoggingConfiguration();
config.AddLogSource("General", SourceLevels.All, true)
.AddTraceListener(flatFileTraceListener);
config.Filters.Add(enabledFilter);
LogWriter defaultWriter = new LogWriter(config);
defaultWriter.Write("Test1", "General");
var filter = defaultWriter.GetFilter<LogEnabledFilter>();
filter.Enabled = false;
defaultWriter.Write("Test2", "General");
успеха! Второе сообщение («Test2») не было зарегистрировано.
Итак, что здесь происходит? Если мы сами создадим фильтр и добавим его в конфигурацию, он работает, но при использовании конфигурации Enterprise Library значение фильтра не обновляется.
Это приводит к гипотезе: при использовании конфигурации Enterprise Library новые экземпляры фильтров возвращаются каждый раз, поэтому изменение значения не влияет на внутренний экземпляр, используемый корпоративной библиотекой.
Если мы копаем код корпоративной библиотеки, мы (в конечном итоге) нажимаем на класс LoggingSettings
и метод BuildLogWriter
. Это используется для создания LogWriter. Вот где создаются фильтры:
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter());
Так эта линия использует сконфигурированный LogFilterData
и вызов метода BuildFilter для создания экземпляра применимого фильтра. В этом случае BuildFilter
метод класса конфигурации LogEnabledFilterData
BuildFilter
метода возвращает экземпляр LogEnabledFilter
:
return new LogEnabledFilter(this.Name, this.Enabled);
Проблема с этим кодом, что this.LogFilters.Select
возвращает ленивое оцененное перечисление, которое создает LogFilters
и это перечисление передается в LogWriter, который будет использоваться для всех манипуляций с фильтрами. Каждый раз, когда на фильтрах ссылаются, перечисление оценивается и создается новый экземпляр фильтра! Это подтверждает первоначальную гипотезу.
Чтобы сделать это явным: каждый раз, когда вызывается LogWriter.Write(), новый LogEnabledFilter
создается на основе исходной конфигурации. Когда фильтры запрашиваются путем вызова GetFilter()
, новый LogEnabledFilter
создается на основе исходной конфигурации. Любые изменения в объекте, возвращаемые GetFilter()
, не влияют на внутреннюю конфигурацию, так как это новый экземпляр объекта и, во всяком случае, внутренняя корпоративная библиотека создаст еще один новый экземпляр в следующем вызове Write()
.
Во-первых, это просто неправильно, но также неэффективно создавать новые объекты при каждом вызове Write()
, которые можно было бы вызвать много раз ..
легко исправить эту проблему, чтобы оценить LogFilters перечисление по телефону ToList()
:
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter()).ToList();
Это оценивает перечисление только один раз, обеспечивая, что только один экземпляр создается фильтр. Тогда будет использоваться метод GetFilter()
и значение фильтра обновления, опубликованное в вопросе.
Рэнди, спасибо за подробное объяснение! Я загрузил последний исходный код для EL6, и я реализовал это исправление, но я не могу создать исходный код, используя BuildLibrary.bat в своей системе. Не могли бы вы взглянуть на этот вопрос (http://stackoverflow.com/questions/39546020/how-to-rebuild-enterprise-library-6-on-win-8-and-vs2015) – Legends
Хорошо, сделанный. Я получил его для работы, используя ваше исправление. Большое спасибо! – Legends
FYI, после исправления, я повторно запустил тесты Unit и BVT и не видел никаких повреждений из-за изменения. –