Как сохранить коллекцию пользовательских объектов в файле user.config?
Я хотел бы сохранить коллекцию пользовательских объектов в файле 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="[email protected]" />
<User firstName="Jane" lastName="Doe" email="[email protected]" />
</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;
}
}
Я сделал все это после этой статьи . Однако, используя этот подход, я могу читать настройки из app.config в коллекцию List<UserInfo>
, но мне также нужно будет написать измененный список обратно,
Я искал документацию без успеха, и теперь я как бы застрял. Что мне не хватает?
Ответы
Ответ 1
Я бы не хранил такие данные в app.config, по крайней мере, не в том случае, если он должен быть обновлен программно. Понятно, что это для параметров конфигурации, а не для данных приложения, поэтому, возможно, вы хотите сохранить информацию о своем имени пользователя и пароле в отдельном файле XML (при условии, что вы не можете или не хотите использовать базу данных)?
Сказав это, я думаю, что ваш лучший выбор - прочитать в app.config как стандартный XML файл, проанализировать его, добавить нужные вам узлы и записать его обратно. Встроенный API ConfigurationManager не предлагает способ записи новых параметров (что, я полагаю, дает подсказку относительно предполагаемого использования Microsoft).
Ответ 2
Способ добавления настраиваемой конфигурации (если вам требуется больше, чем просто простых типов) - использовать 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, хотя он действительно должен следовать шаблону объявления каждого свойства полностью, как описано в этой превосходной статье CodeProject, Как вы можете видеть, он представляет собой "пользовательские" элементы в вашей конфигурации, которые вы предоставили.
Класс 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="[email protected]" />
<user firstName="Jane" lastName="Doe" email="[email protected]" />
</userInfo>
</configuration>
Как вы можете видеть, в этом примере я включил некоторые элементы userInfo/user в App.config. Я также добавил настройки, чтобы сказать, что они могут быть определены на уровне машинного/прикладного/пользовательского/роуминг-пользователя.
Далее нам нужно знать, как обновлять их во время выполнения, следующий код показывает пример:
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();
Приведенный выше код создаст новый файл user.config, если он понадобится, занесенный глубоко в папку "Локальные настройки\Данные приложения" для пользователя.
Если вместо этого вы хотите, чтобы новый пользователь, добавленный в файл app.config, просто изменил параметр для метода OpenExeConfiguration() на ConfigurationUserLevel.None.
Как вы можете видеть, это достаточно просто, хотя найти эту информацию потребовалось немного копания.
Ответ 3
Используйте новый API System.Configuration из .Net Framework 2.
(Assembly: System.Configuration) IConfigurationSectionHandler устарел.
Вы можете найти много очень хороших образцов и описаний на http://www.codeproject.com/KB/dotnet/mysteriesofconfiguration.aspx
Существует также пример кода, о том, как вы можете изменять и сохранять значения.
EDIT: Соответствующая часть документации в кодепроекте
Сохраняет только измененные значения, если существуют какие-либо изменения.
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">
Вот так)
Если вы хотите использовать не attibutes, а свойства, просто создайте класс, полученный из ConfigurationElement, и включите его в свой класс, защищенный от ConfigurationSettings.