我想在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>
集合,但我还需要编写一个修改过的列表回来。
我正在搜索文档但没有成功,现在我有点卡住了。我错过了什么?
答案 0 :(得分:55)
添加自定义配置的方法(如果您需要的不仅仅是简单类型)是使用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类只支持具有多个“user”元素,包括如果要在运行时修改它,可以添加/删除/清除集合中的项目。
最后有UserInfoSection,它只是统计它有一个默认的“user”元素集合。
接下来是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。
正如你所看到的,它相当简单,虽然找到这些信息需要一些挖掘。
答案 1 :(得分:7)
我不会将这种数据存储在app.config中,至少不会以编程方式进行更新。从概念上讲,它是用于配置设置,而不是应用程序数据,所以您可能希望将用户名和密码信息存储在单独的XML文件中(假设您不能或不想使用数据库)?
话虽如此,我认为最好的办法是将app.config作为标准XML文件读取,解析它,添加所需的节点并将其写回。内置的ConfigurationManager API不提供回写新设置的方法(我想这给出了微软预期用途的提示)。
答案 2 :(得分:1)
使用.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枚举具有以下值:
答案 3 :(得分:0)
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());
}
}
答案 4 :(得分:-1)
你应该创建一个类:
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">
就是这样) 如果您不想使用attibutes,而是使用属性,只需创建从ConfigurationElement派生的类,并将其包含在从ConfigurationSettings中定义的类中。