是否可以从外部文件初始化ConfigurationSection ?



我在我的应用程序中有一个自定义配置属性,它看起来像这样:

public class OverrideConfiguration : ConfigurationSection
{
    [ConfigurationProperty(PROP_ADMIN_CONNSTR)]
    public StringConfigurationElement AdminConnectionString
    {
        get { return base[PROP_ADMIN_CONNSTR] as StringConfigurationElement; }
        set { base[PROP_ADMIN_CONNSTR] = value; }
    }
    // .. Various other properties, but you get the idea
}

然而,我想要的是允许.config文件指向外部文件源。像这样:

<ServiceOverrides file="Overrides.local.config" />
现在,内置的configSource属性与我需要的接近,但是它有两个主要问题。
  1. 文件必须存在如果文件不存在,就会出错。
  2. 文件必须在当前目录或更深的目录中。换句话说,我不能指向..Overrides.local.config

我想要的与<appSettings file="..." />配置元素几乎相同。然而,该属性似乎是appSettings实现的东西,而不是基本ConfigurationSection类的一部分。

我的问题:

是否有可能在ConfigurationSection中重写一些东西,基本上会从不同的位置读取XML数据?我不想改变我的类的任何其他方面,也不想做我自己的XML反序列化或任何事情。我只是想检查一个文件是否存在,如果存在,从文件加载XML内容,否则加载默认XML内容。

好了,我有一个可行的解决方案。我不确定这是否是最好的方法,但它确实看起来像我想要的那样工作。

private readonly Queue<String> externalSources = new Queue<String>();
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
    var externalFile = reader.GetAttribute("File");
    if(!String.IsNullOrWhiteSpace(externalFile))
    {
        externalSources.Enqueue(externalFile);
    }
    base.DeserializeElement(reader, serializeCollectionKey);
}
protected override void PostDeserialize()
{
    base.PostDeserialize();
    // Override data with local stuff
    if (externalSources.Count == 0) return;
    string file = externalSources.Dequeue();
    if (System.IO.File.Exists(file))
    {
        var reader = XmlReader.Create(file);
        base.DeserializeSection(reader);
    }
}

首先,我捕获DeserializeElement事件,该事件在读取<ServiceOverrides>元素时发生。我们检查它是否有File属性,如果有,我们将它添加到一个外部源队列中来加载。

接下来,我们捕获PostDeserialize事件,该事件在解析完所有本地XML后被调用。如果队列中有外部源,我们将它从队列中取出,检查它是否确实存在,然后用该文件的内容创建一个XmlReader。现在我们可以简单地再次调用DeserializeSection 并传入我们的新阅读器。ConfigurationSection类非常聪明,可以直接覆盖添加到现有配置中的任何新数据。我最后得到的是两个配置文件的聚合,其中include文件在重复的情况下胜出。

这个队列是怎么回事?似乎每次调用DeserializeSection,它都会再次调用PostDeserialize。因此,如果我们简单地捕获PostDeserialize,检查File属性,并再次调用DeserializeSection,我们将进入无限循环。我们可以使用标志来记住我们是否已经加载了外部文件,但是队列有一个额外的好处,允许包含文件加载更多的包含文件(并不是说我想这样做,但你可能会这样做)。

提示:这可能会很好地工作,并且很容易理解,但如果您在生产代码中使用它,则有一些事情可以改进。首先,externalSources不需要真正的是一个队列,因为这些调用实际上不是递归的。您可能只使用string,并在处理完该文件后将其设置为null。其次,在循环包含链的情况下,这可能导致无限循环。您可以为先前包含的文件创建一个List<T>,然后在将其添加到队列之前检查该包含是否已经存在于该列表中。

希望这能帮助到一些人!

相关内容

  • 没有找到相关文章

最新更新