[英]Is it possible to initialize a ConfigurationSection from an external file?
I have a custom configuration property in my app. 我的应用程序中有一个自定义配置属性。 It looks something like this:
看起来像这样:
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
}
However, what I'd like is to allow the .config file to be pointed to an external file source. 但是,我要允许.config文件指向外部文件源。 Something like this:
像这样:
<ServiceOverrides file="Overrides.local.config" />
Now, the built-in configSource
attribute is close to what I need, but it has two major issues. 现在,内置的
configSource
属性接近我需要的属性,但是有两个主要问题。
..\\Overrides.local.config
..\\Overrides.local.config
What I want is pretty much identical to the <appSettings file="..." />
configuration element. 我想要的与
<appSettings file="..." />
配置元素几乎相同。 However, that attribute seems to be something appSettings
implemented, and is not part of the base ConfigurationSection
class. 但是,该属性似乎是由
appSettings
实现的,并且不是基本ConfigurationSection
类的一部分。
My Question: 我的问题:
Is it possible to override something in ConfigurationSection
that will basically read XML data from a different location? 是否有可能重写
ConfigurationSection
中的某些内容,这些内容基本上将从其他位置读取XML数据? I don't want to change any other aspect of my class or do my own XML deserialization or anything. 我不想更改类的任何其他方面,也不想做自己的XML反序列化或任何其他事情。 I simply want to check if a file exists, if so, load in the XML contents from that file, otherwise load in the default XML contents.
我只想检查文件是否存在,如果存在,则从该文件中加载XML内容,否则加载默认XML内容。
Ok, I have a working solution. 好的,我有一个可行的解决方案。 I'm not sure if it's the best approach, but it does appear to work exactly how I want.
我不确定这是否是最好的方法,但是它确实可以按照我的要求工作。
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);
}
}
First, I trap the DeserializeElement
event, which happens when we read the <ServiceOverrides>
element. 首先,我捕获
DeserializeElement
事件,该事件在我们读取<ServiceOverrides>
元素时发生。 We check if it has a File
attribute, and if so we add it to a queue of external sources to load. 我们检查它是否具有
File
属性,如果是,我们将其添加到要加载的外部源队列中。
Next, we trap the PostDeserialize
event, which gets called after all the local XML is parsed. 接下来,我们捕获
PostDeserialize
事件,该事件在解析所有本地XML之后被调用。 If there's an external source in the queue, we dequeue it, check if it actually exists, then create an XmlReader
with the contents of that file. 如果队列中有外部源,我们将其出队,检查它是否确实存在,然后使用该文件的内容创建一个
XmlReader
。 Now we can simply call DeserializeSection
again and pass in our new reader. 现在我们可以简单地再次调用
DeserializeSection
并传入新的阅读器。 The ConfigurationSection
class is smart enough to just overwrite or append any new data to the existing configuration. ConfigurationSection
类足够聪明,可以将任何新数据覆盖或附加到现有配置中。 What I get at the end is an aggregation of both configuration files, where the include file wins in the event of a duplicate. 最后我得到的是两个配置文件的聚合,其中包含文件在重复的情况下胜出。
Now, what's this nonsense with the queue? 现在,队列有什么废话? Well, it seems every time you call
DeserializeSection
, it'll call PostDeserialize
again. 好吧,似乎每次您调用
DeserializeSection
,它都会再次调用PostDeserialize
。 So, if we simply trapped PostDeserialize
, check the File
attribute, and call DeserializeSection
again, we'd get in an infinite loop. 因此,如果我们简单地捕获
PostDeserialize
,检查File
属性,然后再次调用DeserializeSection
,我们将陷入无限循环。 We could just use a flag to remember if we already loaded the external file, but a queue has the added benefit of allowing the include file to load more include files (not that I'd ever want to do that, but you might). 我们可以仅使用一个标志来记住是否已经加载了外部文件,但是队列的另一个好处是允许包含文件加载更多的包含文件(不是我想这样做,但您可以这样做)。
Tips: This will probably work fairly well, and is simple to understand, but if you're using it in production code, there's a few things you could improve on. 提示:这可能会很好地工作,并且很容易理解,但是如果您在生产代码中使用它,则可以在某些方面进行改进。 First,
externalSources
doesn't really need to be a queue, since these calls aren't actually recursive. 首先,
externalSources
并不真正需要的是一个队列,因为这些电话实际上并不是递归的。 You can probably just use a string
, and set it to null after you're done processing that file. 在处理完该文件之后,您可以只使用一个
string
,并将其设置为null。 Second, this could cause an infinite loop in the event of a circular include chain. 其次,这可能在循环包含链的情况下导致无限循环。 You could create a
List<T>
of previously included files, then check if the include already exists in that list before adding it to the queue. 您可以创建先前包含的文件的
List<T>
,然后在将其添加到队列之前检查该列表中是否已包含该文件。
Hope this helps someone! 希望这对某人有帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.