C# 如何将自定义对象的集合存储到 user.config 文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/734474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:07:21  来源:igfitidea点击:

How to store a collection of custom objects to an user.config file?

c#configurationcollectionsapp-config

提问by Dirk Vollmar

I would like to store a collection of custom objects in a user.config file and would like to add and remove items from the collection programmatically and then save the modified list back to the configuration file.

我想在 user.config 文件中存储一组自定义对象,并想以编程方式从集合中添加和删除项目,然后将修改后的列表保存回配置文件。

My items are of the following simple form:

我的物品具有以下简单形式:

class UserInfo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }        
}

In my app.config I already created a custom section:

在我的 app.config 中,我已经创建了一个自定义部分:

<configuration>
  <configSections>
    <section name="userInfo" type="UserInfoConfigurationHandler, MyProgram"/>

  </configSections>
  <userInfo>
    <User firstName="John" lastName="Doe" email="[email protected]" />
    <User firstName="Jane" lastName="Doe" email="[email protected]" />
  </userInfo>

</configuration>

I am also able to read in the settings by implementing IConfigurationSectionHandler:

我还可以通过实现来读取设置IConfigurationSectionHandler

class UserInfoConfigurationHandler : IConfigurationSectionHandler
{
    public UserInfoConfigurationHandler() { }

    public object Create(object parent, object configContext, System.Xml.XmlNode section)
    {
        List<UserInfo> items = new List<UserInfo>();
        System.Xml.XmlNodeList processesNodes = section.SelectNodes("User");

        foreach (XmlNode processNode in processesNodes)
        {
            UserInfo item = new UserInfo();
            item.FirstName = processNode.Attributes["firstName"].InnerText;
            item.LastName = processNode.Attributes["lastName"].InnerText;
            item.Email = processNode.Attributes["email"].InnerText;
            items.Add(item);
        }
        return items;
    }
}

I did all this following this article. However, using this approach I'm only able to readthe settings from app.config into a List<UserInfo>collection, but I would also need to writea modified list back.

我在这篇文章之后做了这一切。但是,使用这种方法我只能将app.config 中的设置List<UserInfo>集合,但我还需要写回修改后的列表。

I was searching the documentation without success and now I'm kind of stuck. What am I missing?

我正在搜索文档但没有成功,现在我有点卡住了。我错过了什么?

采纳答案by Dana

I wouldn't store that kind of data in an app.config, at least not if it's meant to be updated programatically. Conceptually, it's for configuration settings, not application data so perhaps you want to store your username and password info in a separate XML file (assuming you can't or don't want to use a database)?

我不会将这种数据存储在 app.config 中,至少如果它打算以编程方式更新的话。从概念上讲,它用于配置设置,而不是应用程序数据,所以也许您想将用户名和密码信息存储在单独的 XML 文件中(假设您不能或不想使用数据库)?

Having said that, then I think your best bet is to read in the app.config as a standard XML file, parse it, add the nodes you want and write it back. The built in ConfigurationManager API doesn't offer a way to write back new settings (which I suppose gives a hint as to Microsoft's intended use).

话虽如此,我认为最好的办法是将 app.config 作为标准 XML 文件读入,解析它,添加所需的节点并将其写回。内置的 ConfigurationManager API 不提供写回新设置的方法(我想这暗示了 Microsoft 的预期用途)。

回答by Michael Piendl

Use the newSystem.Configuration API from .Net Framework 2.(Assembly: System.Configuration)IConfigurationSectionHandler is obsolete.

使用来自 .Net Framework 2System.Configuration API (程序集:System.Configuration)IConfigurationSectionHandler 已过时。

You can find a lot of very good samples and descriptions at http://www.codeproject.com/KB/dotnet/mysteriesofconfiguration.aspx

您可以在http://www.codeproject.com/KB/dotnet/mysteriesofconfiguration.aspx找到许多非常好的示例和说明

There is also a code sample, about how you can modify and save values.

还有一个代码示例,介绍如何修改和保存值。



EDIT:Relevant part of the documentation in codeproject

编辑:codeproject 中文档的相关部分

Saves only modified values if any changes exist

如果存在任何更改,则仅保存修改后的值

Configuration.Save() 

Saves the specified level of changes, if any changes exist

保存指定级别的更改(如果存在任何更改)

Configuration.Save(ConfigurationSaveMode) 

Saves the specified level of changes, forcing a save to take place if the second parameter is true

保存指定级别的更改,如果第二个参数为真,则强制进行保存

Configuration.Save(ConfigurationSaveMode, bool)

The ConfigurationSaveMode enumeration has the following values:

ConfigurationSaveMode 枚举具有以下值:

  • Full- Saves all configuration properties, whether they have changed or not
  • Modified- Saves properties that have been modified, even if the current value is the same as the original
  • Minimal- Saves only properties that have been modified and have different values than the original
  • 完整- 保存所有配置属性,无论它们是否已更改
  • Modified- 保存已修改的属性,即使当前值与原始值相同
  • 最小- 仅保存已修改且值与原始值不同的属性

回答by 0100110010101

you should create a class like:

你应该创建一个类,如:

public class MySettings : ConfigurationSection 
{
    public MySettings Settings = (MySettings)WebConfigurationManager.GetSection("MySettings");

    [ConfigurationProperty("MyConfigSetting1")]
    public string DefaultConnectionStringName
    {
        get { return (string)base["MyConfigSetting1"]; }
        set { base["MyConfigSetting1"] = value; }
    }
}

after that in your web.config use:

之后在你的 web.config 中使用:

<section name="MySettings" type="MyNamespace.MySettings"/>
<MySettings MyConfigSetting1="myValue">

That's the way) If you want to use not attibutes, but properties, just create the class derived from ConfigurationElement and include it to your class defived from ConfigurationSettings.

就是这样)如果您不想使用属性,而是使用属性,只需创建从 ConfigurationElement 派生的类并将其包含到您的从 ConfigurationSettings 定义的类中。

回答by Timothy Walters

The way to add custom config (if you require more than just simple types) is to use a ConfigurationSection, within that for the schema you defined you need a ConfigurationElementCollection (set as default collection with no name), which contains a ConfigurationElement, as follows:

添加自定义配置的方法(如果您需要的不仅仅是简单类型)是使用 ConfigurationSection,在您定义的架构中,您需要一个 ConfigurationElementCollection(设置为没有名称的默认集合),其中包含一个 ConfigurationElement,如下所示:

public class UserElement : ConfigurationElement
{
    [ConfigurationProperty( "firstName", IsRequired = true )]
    public string FirstName
    {
        get { return (string) base[ "firstName" ]; }
        set { base[ "firstName" ] = value;}
    }

    [ConfigurationProperty( "lastName", IsRequired = true )]
    public string LastName
    {
        get { return (string) base[ "lastName" ]; }
        set { base[ "lastName" ] = value; }
    }

    [ConfigurationProperty( "email", IsRequired = true )]
    public string Email
    {
        get { return (string) base[ "email" ]; }
        set { base[ "email" ] = value; }
    }

    internal string Key
    {
        get { return string.Format( "{0}|{1}|{2}", FirstName, LastName, Email ); }
    }
}

[ConfigurationCollection( typeof(UserElement), AddItemName = "user", CollectionType = ConfigurationElementCollectionType.BasicMap )]
public class UserElementCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new UserElement();
    }

    protected override object GetElementKey( ConfigurationElement element )
    {
        return ( (UserElement) element ).Key;
    }

    public void Add( UserElement element )
    {
        BaseAdd( element );
    }

    public void Clear()
    {
        BaseClear();
    }

    public int IndexOf( UserElement element )
    {
        return BaseIndexOf( element );
    }

    public void Remove( UserElement element )
    {
        if( BaseIndexOf( element ) >= 0 )
        {
            BaseRemove( element.Key );
        }
    }

    public void RemoveAt( int index )
    {
        BaseRemoveAt( index );
    }

    public UserElement this[ int index ]
    {
        get { return (UserElement) BaseGet( index ); }
        set
        {
            if( BaseGet( index ) != null )
            {
                BaseRemoveAt( index );
            }
            BaseAdd( index, value );
        }
    }
}

public class UserInfoSection : ConfigurationSection
{
    private static readonly ConfigurationProperty _propUserInfo = new ConfigurationProperty(
            null,
            typeof(UserElementCollection),
            null,
            ConfigurationPropertyOptions.IsDefaultCollection
    );

    private static ConfigurationPropertyCollection _properties = new ConfigurationPropertyCollection();

    static UserInfoSection()
    {
        _properties.Add( _propUserInfo );
    }

    [ConfigurationProperty( "", Options = ConfigurationPropertyOptions.IsDefaultCollection )]
    public UserElementCollection Users
    {
        get { return (UserElementCollection) base[ _propUserInfo ]; }
    }
}

I've kept the UserElement class simple, although it really should follow the pattern of declaring each property fully as described in this excellent CodeProject article. As you can see it represents the "user" elements in your config you provided.

我一直保持 UserElement 类的简单,尽管它确实应该遵循这篇优秀的 CodeProject 文章 中描述的完全声明每个属性的模式。如您所见,它代表您提供的配置中的“用户”元素。

The UserElementCollection class simply supports having more than one "user" element, including the ability to add/remove/clear items from the collection if you want to modify it at run-time.

UserElementCollection 类只支持拥有多个“用户”元素,包括在运行时修改集合中添加/删除/清除项目的能力。

Lastly there is the UserInfoSection which simply stats that it has a default collection of "user" elements.

最后是 UserInfoSection,它只是统计它有一个默认的“用户”元素集合。

Next up is a sample of the App.config file:

接下来是 App.config 文件的示例:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup>
      <section
        name="userInfo"
        type="ConsoleApplication1.UserInfoSection, ConsoleApplication1"
        allowDefinition="Everywhere"
        allowExeDefinition="MachineToLocalUser"
      />
    </sectionGroup>
  </configSections>

  <userInfo>
    <user firstName="John" lastName="Doe" email="[email protected]" />
    <user firstName="Jane" lastName="Doe" email="[email protected]" />
  </userInfo>
</configuration>

As you can see, in this example I've included some userInfo/user elements in the App.config. I've also added settings to say they can be defined at machine/app/user/roaming-user levels.

如您所见,在本示例中,我在 App.config 中包含了一些 userInfo/user 元素。我还添加了一些设置,说明它们可以在机器/应用程序/用户/漫游用户级别进行定义。

Next we need to know how to update them at run-time, the following code shows an example:

接下来我们需要知道如何在运行时更新它们,下面的代码展示了一个例子:

Configuration userConfig = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );

var userInfoSection = userConfig.GetSection( "userInfo" ) as UserInfoSection;

var userElement = new UserElement();

userElement.FirstName = "Sample";
userElement.LastName = "User";
userElement.Email = "[email protected]";

userInfoSection.Users.Add( userElement );

userConfig.Save();

The above code will create a new user.config file if needed, buried deep inside the "Local Settings\Application Data" folder for the user.

如果需要,上面的代码将创建一个新的 user.config 文件,为用户深埋在“Local Settings\Application Data”文件夹中。

If instead you want the new user added to the app.config file simply change the parameter for the OpenExeConfiguration() method to ConfigurationUserLevel.None.

相反,如果您希望将新用户添加到 app.config 文件,只需将 OpenExeConfiguration() 方法的参数更改为 ConfigurationUserLevel.None。

As you can see, it's reasonably simple, although finding this information required a bit of digging.

如您所见,它相当简单,尽管找到此信息需要进行一些挖掘。

回答by Pandurang Kumbhar

 private void frmLocalFileTransfer_Load(object sender, EventArgs e)
    {
        try
        {
            dt.Columns.Add("Provider");
            dt.Columns.Add("DestinationPath");
            string[] folders = null;
            dt.Columns.Add("SourcePath");

            for (int i = 1; i < System.Configuration.ConfigurationManager.ConnectionStrings.Count; i++)
            {
                string key = System.Configuration.ConfigurationManager.ConnectionStrings[i].Name;
                string constr = System.Configuration.ConfigurationManager.ConnectionStrings[i].ConnectionString;
                DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
                folders = constr.Split('\');
                string newstr = (folders[folders.Length - 2]);
                if (!newstr.Contains("BackUp"))
                {
                    DataRow row = dt.NewRow();
                    row[dt.Columns[0].ToString()] = key;
                    row[dt.Columns[1].ToString()] = constr;
                    row[dt.Columns[2].ToString()] = constr;
                    dt.Rows.InsertAt(row, i - 1);
                }
            }

            foreach (DataColumn dc in dt.Columns)
            {
                DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
                column.DataPropertyName = dc.ColumnName;
                column.HeaderText = dc.ColumnName;
                column.Name = dc.ColumnName;
                column.SortMode = DataGridViewColumnSortMode.Automatic;
                column.ValueType = dc.DataType;
                GVCheckbox();

                gevsearch.Columns.Add(column);
            }
            if (gevsearch.ColumnCount == 4)
            {
                DataGridViewButtonColumn btnColoumn = new DataGridViewButtonColumn();
                btnColoumn.Width = 150;
                btnColoumn.HeaderText = "Change SourcePath";
                btnColoumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
                gevsearch.Columns.Insert(4, btnColoumn);


            }
             gevsearch.DataSource = dt;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

private void btnAddProvider_Click(object sender, EventArgs e)
    {
        try
        {
            System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
            path = "D:\Pandurang\Jitendra\LocalFileTransfer\LocalFileTransfer
            xDoc.Load(path);
            System.Xml.XmlElement element = xDoc.CreateElement("add");
            element.SetAttribute("name", txtProviderName.Text.Trim());
            element.SetAttribute("connectionString", txtNewPath.Text.Trim());
            System.Xml.XmlElement elementBackup = xDoc.CreateElement("add");
            elementBackup.SetAttribute("name", BackUpName);
            elementBackup.SetAttribute("connectionString", txtBackupPath.Text.Trim());
            System.Xml.XmlNode node= xDoc.ChildNodes[1].ChildNodes[0];
            node.AppendChild(element);
            node.AppendChild(elementBackup);
            xDoc.Save(path);
          }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }