【问题标题】:Where am I going wrong with ConfigurationSections? [duplicate]ConfigurationSections 哪里出错了? [复制]
【发布时间】:2015-01-17 16:48:27
【问题描述】:

我正在尝试实现一个自定义配置部分,以便我可以加载用户定义的项目列表,但运气不佳。我已经阅读了以下帖子,但我仍然无法弄清楚我做错了什么。他们似乎是很好的指南,但我在这里遗漏了一些重要的事实。我希望有人能指出具体是什么。

这是我的测试。当我单步执行时,config 仍然为空。这就像对GetSection 的调用什么都不做。

[TestClass]
public class ToDoConfigTests
{
    [TestMethod]
    public void TestGetTodoAttribute()
    {
        var config = ConfigurationManager.GetSection("ToDoListAttributesSection") as ToDoItemsConfigurationSection;

        Assert.Fail();

    }
}

我的配置类:

using System.Configuration;
using Rubberduck.ToDoItems;

namespace Rubberduck.Config
{

    public class ToDoItemsConfigurationCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new ToDoListAttributeElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ToDoListAttributeElement)element).Comment;
        }
    }

    public class ToDoItemsConfigurationSection : ConfigurationSection
    {
        [ConfigurationProperty("ToDoListAttributes", IsRequired = true, IsDefaultCollection=true)]
        public ToDoItemsConfigurationCollection ToDoListAttributes
        {
            get { return (ToDoItemsConfigurationCollection)this["ToDoListAttributes"]; }
            set { this["ToDoListAttributes"] = value; }
        }
    }

    public class ToDoListAttributeElement : ConfigurationElement
    {
        [ConfigurationProperty("TaskPriority", DefaultValue = TaskPriority.Low, IsRequired = true)]
        public TaskPriority Priority
        {
            get { return (TaskPriority)this["TaskPriority"]; }
            set { this["TaskPriority"] = value; }
        }

        [ConfigurationProperty("Comment",IsKey=true, IsRequired = true)]
        public string Comment
        {
            get { return (string)this["Comment"]; }
            set { this["Comment"] = value; }
        }
    }
}

最后是 app.config 文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="Rubberduck.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
        <section name="ToDoListAttributesSection" type="Rubberduck.Config.ToDoItemsConfigurationSection, Rubberduck.Config"/>
    </configSections>
    <ToDoListAttributesSection>
      <ToDoListAttributes>
        <add Comment="note" TaskPriority="0" />
        <add Comment="todo" TaskPriority="1" />
        <add Comment="bug" TaskPriority="2"/>
      </ToDoListAttributes>
    </ToDoListAttributesSection>
</configuration>

【问题讨论】:

  • 我刚试过@GrantWinney。它仍然为空。

标签: c# configuration app-config


【解决方案1】:

为什么这不起作用的秘密与我在写这个问题时没有分享的关于我的软件的细节有关。

我的应用程序不是一个独立的应用程序。它是 VBA 编辑器的 COM 插件。因此,它是一个 *.dll 文件,而不是 *.exe。 App.config 文件仅适用于正在执行的程序集(*.exe),这就是我的代码不起作用的原因。有一个few good solutions here,但我最终使用XML Serialization 得到rolling my own configuration

以下是我最终使用的代码。如果您更喜欢在那里查看,也可以找到in the Rubberduck repository hosted on GitHub

解决方案的核心是IConfigurationService 接口和ConfigurationLoader 实现,它允许我读取和写入存储配置的xml 文件。 (这里的版本已经简化,只处理原始代码。)

IConfigurationService:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace Rubberduck.Config
{
    [ComVisible(false)]
    public interface IConfigurationService
    {
        Configuration GetDefaultConfiguration();
        ToDoMarker[] GetDefaultTodoMarkers();
        Configuration LoadConfiguration();
        void SaveConfiguration<T>(T toSerialize);
    }
}

配置加载器:

public class ConfigurationLoader : IConfigurationService
{
    private static string configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Rubberduck", "rubberduck.config");

    /// <summary>   Saves a Configuration to Rubberduck.config XML file via Serialization.</summary>
    public void SaveConfiguration<T>(T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
        using (TextWriter textWriter = new StreamWriter(configFile))
        {
            xmlSerializer.Serialize(textWriter, toSerialize);
        }
    }

    /// <summary>   Loads the configuration from Rubberduck.config xml file. </summary>
    /// <remarks> If an IOException occurs, returns a default configuration.</remarks>
    public Configuration LoadConfiguration()
    {
        try
        {
            using (StreamReader reader = new StreamReader(configFile))
            {
                var deserializer = new XmlSerializer(typeof(Configuration));
                var config = (Configuration)deserializer.Deserialize(reader);

                //deserialization can silently fail for just parts of the config, 
                //  so we null check and return defaults if necessary.
                if (config.UserSettings.ToDoListSettings == null)
                {
                    config.UserSettings.ToDoListSettings = new ToDoListSettings(GetDefaultTodoMarkers());
                }

                return config;
            }
        }
        catch (IOException)
        {
            return GetDefaultConfiguration();
        }
        catch (InvalidOperationException ex)
        {
            var message = ex.Message + System.Environment.NewLine + ex.InnerException.Message + System.Environment.NewLine + System.Environment.NewLine +
                    configFile + System.Environment.NewLine + System.Environment.NewLine +
                    "Would you like to restore default configuration?" + System.Environment.NewLine + 
                    "Warning: All customized settings will be lost.";

            DialogResult result = MessageBox.Show(message, "Error Loading Rubberduck Configuration", MessageBoxButtons.YesNo,MessageBoxIcon.Exclamation);

            if (result == DialogResult.Yes)
            {
                var config = GetDefaultConfiguration();
                SaveConfiguration<Configuration>(config);
                return config;
            }
            else
            {
                throw ex;
            }
        }
    }

    public Configuration GetDefaultConfiguration()
    {
        var userSettings = new UserSettings(new ToDoListSettings(GetDefaultTodoMarkers()));

        return new Configuration(userSettings);
    }

    public ToDoMarker[] GetDefaultTodoMarkers()
    {
        var note = new ToDoMarker("NOTE:", TodoPriority.Low);
        var todo = new ToDoMarker("TODO:", TodoPriority.Normal);
        var bug = new ToDoMarker("BUG:", TodoPriority.High);

        return new ToDoMarker[] { note, todo, bug };
    }
}

配置:

using System;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.InteropServices;

namespace Rubberduck.Config
{
    [ComVisible(false)]
    [XmlTypeAttribute(AnonymousType = true)]
    [XmlRootAttribute(Namespace = "", IsNullable = false)]
    public class Configuration
    {
        public UserSettings UserSettings { get; set; }

        public Configuration()
        {
            //default constructor required for serialization
        }

        public Configuration(UserSettings userSettings)
        {
            this.UserSettings = userSettings;
        }
    }
}

用户设置:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Runtime.InteropServices;

namespace Rubberduck.Config
{
    [ComVisible(false)]
    [XmlTypeAttribute(AnonymousType = true)]
    public class UserSettings
    {
        public ToDoListSettings ToDoListSettings { get; set; }

        public UserSettings()
        {
            //default constructor required for serialization
        }

        public UserSettings(ToDoListSettings todoSettings)
        {
            this.ToDoListSettings = todoSettings;
        }
    }
}

TodoListSettings:

using System.Xml.Serialization;
using System.Runtime.InteropServices;

namespace Rubberduck.Config
{
    interface IToDoListSettings
    {
        ToDoMarker[] ToDoMarkers { get; set; }
    }

    [ComVisible(false)]
    [XmlTypeAttribute(AnonymousType = true)]
    public class ToDoListSettings : IToDoListSettings
    {
        [XmlArrayItemAttribute("ToDoMarker", IsNullable = false)]
        public ToDoMarker[] ToDoMarkers { get; set; }

        public ToDoListSettings()
        {
            //empty constructor needed for serialization
        }

        public ToDoListSettings(ToDoMarker[] markers)
        {
            this.ToDoMarkers = markers;
        }
    }
}

TodoMarkers:

using System.Xml.Serialization;
using System.Runtime.InteropServices;
using Rubberduck.VBA;

namespace Rubberduck.Config
{
    [ComVisible(false)]
    public enum TodoPriority
    {
        Low, 
        Normal,
        High
    }

    [ComVisible(false)]
    public interface IToDoMarker
    {
        TodoPriority Priority { get; set; }
        string Text { get; set; }
    }

    [ComVisible(false)]
    [XmlTypeAttribute(AnonymousType = true)]
    public class ToDoMarker : IToDoMarker
    {
        //either the code can be properly case, or the XML can be, but the xml attributes must here *exactly* match the xml
        [XmlAttribute]
        public string Text { get; set; }

        [XmlAttribute]
        public TodoPriority Priority { get; set; }

        /// <summary>   Default constructor is required for serialization. DO NOT USE. </summary>
        public ToDoMarker()
        {
            // default constructor required for serialization
        }

        public ToDoMarker(string text, TodoPriority priority)
        {
            Text = text;
            Priority = priority;
        }

        /// <summary>   Convert this object into a string representation. Over-riden for easy databinding.</summary>
        /// <returns>   The Text property. </returns>
        public override string ToString()
        {
            return this.Text;
        }
    }
}

还有一个示例 xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <UserSettings>
    <ToDoListSettings>
      <ToDoMarkers>
        <ToDoMarker Text="NOTE:" Priority="Low" />
        <ToDoMarker Text="TODO:" Priority="Normal" />
        <ToDoMarker Text="BUG:" Priority="High" />
      </ToDoMarkers>
    </ToDoListSettings>
  </UserSettings>
</Configuration>

【讨论】:

    【解决方案2】:

    您的代码看起来不错。它打赌你的集合构造函数中的某些东西有点不对劲。一年前我实现的几乎和你一样,但我使用了ConfigurationGroup,而我的ConfigurationSection 是一个具有属性而不是集合的对象。

    只是为了好玩,你能运行这个吗?

    [TestMethod]
        public void TestGetTodoAttribute()
        {
            ToDoItemsConfigurationSection config= (ToDoItemsConfigurationSection)ConfigurationManager.GetSection("ToDoListAttributesSection");
    
    
            Assert.Fail();
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-11
      • 1970-01-01
      • 2016-08-02
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多