Fluent API 只生效一次(企业库)

Fluent API takes effect only once (Enterprise Library)

我希望使用流利的 api
在运行次修改配置;可能要考虑到外部因素或环境变化。
https://msdn.microsoft.com/en-us/library/ff664363(PandP.50).aspx
但我遇到了问题。问题和下面link一模一样。 Change Enterprise Library configuration midway in a program

此代码适用于 Enterprise Library 6:

class Program
{
    static void Main(string[] args)
    {
        FirstConfig();
        Logger.Write("Before processing", "General"); //Some wrapper around EntLib logger methods

        //Do some processing for some time

        SecondConfig();
        Logger.Write("After after processing", "General");
    }

    private static void FirstConfig()
    {
        var textFormatter = new FormatterBuilder()
            .TextFormatterNamed("First Text Formatter")
            .UsingTemplate("{message}");

        var builder = new ConfigurationSourceBuilder();
        builder.ConfigureLogging()
            .WithOptions.DoNotRevertImpersonation()
            .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory()
            .SendTo.FlatFile("First Listener")
            .FormatWith(textFormatter).WithHeader("").WithFooter("")
            .ToFile("BeforeChange.log");

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);

        Logger.SetLogWriter(new LogWriterFactory(configSource).Create());
    }

    private static void SecondConfig()
    {
        var textFormatter = new FormatterBuilder()
            .TextFormatterNamed("Second Text Formatter")
            .UsingTemplate("{message}");

        var builder = new ConfigurationSourceBuilder();
        builder.ConfigureLogging()
            .WithOptions.DoNotRevertImpersonation()
            .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory()
            .SendTo.FlatFile("Second Listener")
            .FormatWith(textFormatter).WithHeader("").WithFooter("")
            .ToFile("AfterChange.log");

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);

        // Dispose any existing loggers
        Logger.Reset();
        Logger.SetLogWriter(new LogWriterFactory(configSource).Create());
    }
}

在 运行 之后将创建两个日志文件:BeforeChange.log 和 AfterChange.log

对于 EntLib 5,除了需要设置容器外,代码非常相似:

class Program
{
    static void Main(string[] args)
    {
        FirstConfig();
        Logger.Write("Before processing", "General"); //Some wrapper around EntLib logger methods

        //Do some processing for some time

        SecondConfig();
        Logger.Write("After after processing", "General");
    }

    private static void FirstConfig()
    {
        var textFormatter = new FormatterBuilder()
            .TextFormatterNamed("First Text Formatter")
            .UsingTemplate("{message}");

        var builder = new ConfigurationSourceBuilder();
        builder.ConfigureLogging()
            .WithOptions.DoNotRevertImpersonation()
            .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory()
            .SendTo.FlatFile("First Listener")
            .FormatWith(textFormatter).WithHeader("").WithFooter("")
            .ToFile("BeforeChange.log");

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);

        EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
    }

    private static void SecondConfig()
    {
        var textFormatter = new FormatterBuilder()
            .TextFormatterNamed("Second Text Formatter")
            .UsingTemplate("{message}");

        var builder = new ConfigurationSourceBuilder();
        builder.ConfigureLogging()
            .WithOptions.DoNotRevertImpersonation()
            .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory()
            .SendTo.FlatFile("Second Listener")
            .FormatWith(textFormatter).WithHeader("").WithFooter("")
            .ToFile("AfterChange.log");

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);

        // Dispose any existing loggers
        Logger.Reset();
        EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
    }
}

上述 EntLib 5 方法的缺点是第二个配置将配置日志记录,但也会清除已配置的任何其他块。解决办法是直接使用Unity,保持同一个容器,只修改我们想要改变的块。在此示例中,FirstConfig() 配置数据访问和日志记录,但 SecondConfig 仅(重新)配置日志记录。

class Program
{
    private static IUnityContainer container = new UnityContainer();

    static void Main(string[] args)
    {
        FirstConfig();
        Logger.Write("Before processing", "General"); //Some wrapper around EntLib logger methods

        EnterpriseLibraryContainer.Current.GetInstance<Database>("MyDatabase");
        //Do some processing for some time

        SecondConfig();

        // This would fail if we cleared the existing configuration because SecondConfig()
        // does not configure the data access block
        EnterpriseLibraryContainer.Current.GetInstance<Database>("MyDatabase");

        Logger.Write("After after processing", "General");
    }

    private static void FirstConfig()
    {
        var textFormatter = new FormatterBuilder()
            .TextFormatterNamed("First Text Formatter")
            .UsingTemplate("{message}");

        var builder = new ConfigurationSourceBuilder();
        builder.ConfigureLogging()
            .WithOptions.DoNotRevertImpersonation()
            .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory()
            .SendTo.FlatFile("First Listener")
            .FormatWith(textFormatter).WithHeader("").WithFooter("")
            .ToFile("BeforeChange.log");

        builder.ConfigureData()
           .ForDatabaseNamed("MyDatabase")
             .ThatIs.ASqlDatabase()
             .WithConnectionString("server=(local); database=Northwind; Integrated Security=true;")
             .AsDefault();

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);

        container.AddNewExtension<EnterpriseLibraryCoreExtension>();

        // Create a configurator to use to configure our fluent configuration
        var configurator = new UnityContainerConfigurator(container);
        EnterpriseLibraryContainer.ConfigureContainer(configurator, configSource);

        // Use the configured container with fluent config as the Enterprise Library service locator
        EnterpriseLibraryContainer.Current = new UnityServiceLocator(container);
    }

    private static void SecondConfig()
    {
        var textFormatter = new FormatterBuilder()
            .TextFormatterNamed("Second Text Formatter")
            .UsingTemplate("{message}");

        var builder = new ConfigurationSourceBuilder();
        builder.ConfigureLogging()
            .WithOptions.DoNotRevertImpersonation()
            .LogToCategoryNamed("General").WithOptions.SetAsDefaultCategory()
            .SendTo.FlatFile("Second Listener")
            .FormatWith(textFormatter).WithHeader("").WithFooter("")
            .ToFile("AfterChange.log");

        var configSource = new DictionaryConfigurationSource();
        builder.UpdateConfigurationWithReplace(configSource);

        // Dispose any existing loggers
        Logger.Reset();

        var configurator = new UnityContainerConfigurator(container);
        EnterpriseLibraryContainer.ConfigureContainer(configurator, configSource);
    }
}