如何将自定义对象的集合存储到 user.config 文件中?
Posted
技术标签:
【中文标题】如何将自定义对象的集合存储到 user.config 文件中?【英文标题】:How to store a collection of custom objects to an user.config file? 【发布时间】:2010-10-18 13:57:05 【问题描述】:我想将自定义对象的集合存储在 user.config 文件中,并希望以编程方式从集合中添加和删除项目,然后将修改后的列表保存回配置文件。
我的物品有以下简单的形式:
class UserInfo
public string FirstName get; set;
public string LastName get; set;
public string Email get; set;
在我的 app.config 中,我已经创建了一个自定义部分:
<configuration>
<configSections>
<section name="userInfo" type="UserInfoConfigurationHandler, MyProgram"/>
</configSections>
<userInfo>
<User firstName="John" lastName="Doe" email="john@example.com" />
<User firstName="Jane" lastName="Doe" email="jane@example.com" />
</userInfo>
</configuration>
我还可以通过实现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;
我在article 之后做了这一切。但是,使用这种方法,我只能将 app.config 中的设置 读取 到 List<UserInfo>
集合中,但我还需要 write 将修改后的列表返回.
我正在搜索文档但没有成功,现在我有点卡住了。我错过了什么?
【问题讨论】:
+1 反击别人留下的-1,这样的真实问题没必要记下 谢谢帕特里克,这里有很多无缘无故的投票,所以我基本上不在乎;-) 大声笑,好吧,我认为这个问题可能会被更认真地对待,并给予非负面评价:) 非常明智的问题。我有一个类似的问题。 +1 【参考方案1】:添加自定义配置的方法(如果您需要的不仅仅是简单类型)是使用 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 ];
我使 UserElement 类保持简单,尽管它确实应该遵循this excellent CodeProject article 中描述的完全声明每个属性的模式。如您所见,它代表您提供的配置中的“用户”元素。
UserElementCollection 类只支持拥有多个“用户”元素,包括在运行时修改集合时添加/删除/清除集合的能力。
最后是 UserInfoSection,它简单地表明它有一个默认的“用户”元素集合。
接下来是 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="John.Doe@company.com" />
<user firstName="Jane" lastName="Doe" email="Jane.Doe@company.com" />
</userInfo>
</configuration>
如您所见,在此示例中,我在 App.config 中包含了一些 userInfo/user 元素。我还添加了设置以说明它们可以在机器/应用程序/用户/漫游用户级别进行定义。
接下来我们需要知道如何在运行时更新它们,下面的代码展示了一个例子:
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 = "Sample.User@company.com";
userInfoSection.Users.Add( userElement );
userConfig.Save();
如果需要,上面的代码将创建一个新的 user.config 文件,该文件深埋在用户的“Local Settings\Application Data”文件夹中。
如果您希望将新用户添加到 app.config 文件中,只需将 OpenExeConfiguration() 方法的参数更改为 ConfigurationUserLevel.None。
如您所见,这相当简单,但要找到这些信息需要一些挖掘工作。
【讨论】:
Key
getter 是我缺少的部分。非常感谢!
+1:干得好——这将大大增强我的用户配置项目。
@TimothyWalters:看来您可能缺少<sectionGroup>
的开头元素(在您的 app.config sn-p 中)...您有结尾元素,但没有开头。跨度>
刚刚偶然发现您的评论@IAbstract,现已修复,感谢您的关注。【参考方案2】:
我不会将这种数据存储在 app.config 中,至少如果它打算以编程方式更新的话。从概念上讲,它是用于配置设置,而不是应用程序数据,所以也许您想将用户名和密码信息存储在单独的 XML 文件中(假设您不能或不想使用数据库)?
话虽如此,那么我认为最好的办法是将 app.config 作为标准 XML 文件读取,对其进行解析,添加所需的节点并将其写回。内置的 ConfigurationManager API 不提供写回新设置的方法(我想这暗示了微软的预期用途)。
【讨论】:
我同意你的看法,最好将设置存储在 user.config 文件中,但这不是完全相同的 API 吗?在我的例子中,数据实际上是管理员可能会更新的配置数据。 使用简单的名称-值设置保存是没有问题的,但是使用自定义类型似乎变得过于复杂。无论如何,我想我会按照你的建议,简单地忘记 .NET 的配置机制并使用我自己的自定义 XML 配置。【参考方案3】:使用来自 .Net Framework 2.的新 System.Configuration API (程序集:System.Configuration) IConfigurationSectionHandler 已过时。
你可以在http://www.codeproject.com/KB/dotnet/mysteriesofconfiguration.aspx找到很多非常好的示例和描述
还有一个代码示例,关于如何修改和保存值。
编辑: codeproject 中文档的相关部分
如果存在任何更改,则仅保存修改后的值
Configuration.Save()
保存指定级别的更改(如果存在任何更改)
Configuration.Save(ConfigurationSaveMode)
保存指定级别的更改,如果第二个参数为 true,则强制进行保存
Configuration.Save(ConfigurationSaveMode, bool)
ConfigurationSaveMode 枚举具有以下值:
完整 - 保存所有配置属性,无论它们是否已更改 已修改 - 保存已修改的属性,即使当前值与原始值相同 最小 - 仅保存已修改且值与原始值不同的属性【讨论】:
【参考方案4】: 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());
【讨论】:
【参考方案5】:你应该创建一个像这样的类:
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;
之后在您的 web.config 中使用:
<section name="MySettings" type="MyNamespace.MySettings"/>
<MySettings MyConfigSetting1="myValue">
就是这样) 如果您想使用的不是属性,而是属性,只需创建从 ConfigurationElement 派生的类并将其包含到从 ConfigurationSettings 定义的类中。
【讨论】:
以上是关于如何将自定义对象的集合存储到 user.config 文件中?的主要内容,如果未能解决你的问题,请参考以下文章
将自定义对象存储到 NSMutableArray,然后将此 NSMutableArray 存储到 NSUserDefaults
Azure Cosmos SQL API - 如何将自定义对象存储为 @PartitionKey