如何从数据库中的XML读取配置节?

Jon*_*ski 25 .net c# configuration .net-3.5

我有一个像这样的Config类:

public class MyConfig : ConfigurationSection
{
        [ConfigurationProperty("MyProperty", IsRequired = true)]
        public string MyProperty
        {
            get { return (string)this["MyProperty"]; }
            set { this["MyProperty"] = value; }
        }
}
Run Code Online (Sandbox Code Playgroud)

它正在由另一个类实例化

(MyConfig)ConfigurationManager.GetSection("myConfig")
Run Code Online (Sandbox Code Playgroud)

我们正在进行一些更改,现在将配置文件作为xml存储在数据库中,就像它当前在配置文件中一样.

我想将MyConfig维护为ConfigurationSection以实现向后兼容,但仍然可以使用从DB检索的XML字符串来实例化它.

可能吗?如果是这样,怎么样?(请记住它应该仍然可以像上面的实例一样工作)

Sim*_*ier 14

以下是我通常的做法:只需将这些成员添加到MyConfig类:

    public class MyConfig : ConfigurationSection
    {
        private static MyConfig _current;
        public static MyConfig Current
        {
            get
            {
                if (_current == null)
                {
                    switch(ConfigurationStorageType) // where do you want read config from?
                    {
                        case ConfigFile: // from .config file
                            _current = ConfigurationManager.GetSection("MySectionName") as MyConfig;
                            break;

                        case ConfigDb: // from database
                        default:
                            using (Stream stream = GetMyStreamFromDb())
                            {
                                using (XmlTextReader reader = new XmlTextReader(stream))
                                {
                                    _current = Get(reader);
                                }
                            }
                            break;


                    }
                }
                return _current;
            }
        }

        public static MyConfig Get(XmlReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            MyConfig section = new MyConfig();
            section.DeserializeSection(reader);
            return section;
        }
    }
Run Code Online (Sandbox Code Playgroud)

这样,您在MyConfig类中无需更改,但您仍需要使用此类代码更改客户访问它的方式:

string myProp = MyConfig.Current.MyProperty;
Run Code Online (Sandbox Code Playgroud)


Res*_*ing 6

如果需要将任何System.Configuration.ConfigurationSection存储在数据库中,您可以考虑编写通用的部分阅读器,如下所示:

    
public class ConfigurationSectionReader where T : ConfigurationSection, new()
{
    public T GetSection( string sectionXml ) 
    {
        T section = new T();
        using ( StringReader stringReader = new StringReader( sectionXml ) )
        using ( XmlReader reader = XmlReader.Create( stringReader, new XmlReaderSettings() { CloseInput = true } ) )
        {
            reader.Read();
            section.GetType().GetMethod( "DeserializeElement", BindingFlags.NonPublic | BindingFlags.Instance ).Invoke( section, new object[] { reader, true } );
        }
        return section;
    }
}
    

这适用于覆盖DeserializeElement方法的所有类.例如

    
protected override void DeserializeElement( XmlReader reader, bool serializeCollectionKey )
{
    XmlDocument document = new XmlDocument();
    document.LoadXml( reader.ReadOuterXml() );
    MyProperty = document.DocumentElement.HasAttribute( "MyProperty" )
        ? document.DocumentElement.Attributes[ "MyProperty" ].Value
        : string.Empty;
}
    

你可以得到这样一个部分:

    
var reader = new ConfigurationSectionReader();
var section = reader.GetSection( sectionXml ); // where sectionXml is the XML string retrieved from the DB
    


ajm*_*jma 3

我的建议是保留当前的 ​​MyConfig 类,但在构造函数中从数据库加载 XML,然后在 MyConfig 的每个属性中,您可以输入逻辑来确定从何处获取值(数据库或 .config 文件)如果您需要从任一位置提取配置,或者如果该值为空则将其回退。

public class MyConfig : ConfigurationSection
{
    public MyConfig()
    {
        // throw some code in here to retrieve your XML from your database
        // deserialize your XML and store it 
        _myProperty = "<deserialized value from db>";
    }

    private string _myProperty = string.Empty;

    [ConfigurationProperty("MyProperty", IsRequired = true)]
    public string MyProperty
    {
        get
        {
            if (_myProperty != null && _myProperty.Length > 0)
                return _myProperty;
            else
                return (string)this["MyProperty"];
        }
        set { this["MyProperty"] = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)