您是对的,您发布的代码不起作用。该代码使用配置文件 (FileConfigurationSource) 作为配置企业库的方法。
让我们深入挖掘一下,看看编程配置是否可行。
我们将使用 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”)消息。
那么,这里发生了什么?如果我们自己实例化过滤器并将其添加到配置中,它可以工作,但是当依赖企业库配置时,过滤器值不会更新。
这导致了一个假设:当使用企业库配置时,每次都会返回新的过滤器实例,这就是为什么更改值对企业库正在使用的内部实例没有影响的原因。
如果我们深入研究企业库代码,我们(最终)会找到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()
问题中发布的和更新过滤器值方法将起作用。