четверг, 12 июня 2008 г.

Коллекции в конфиге приложения

Задача была следующая. Нужно было написать робота, который будет ходить по тестовому сайту, делать там хиты, прикидываться разными пользователями, делать несколько сессий, да еще и работать на нескольких браузерах. Робот реализован в виде консольного приложения, для работы с браузерами используется Selenium, параметры (количество пользователей, сессий и хитов, а также список браузеров) хранятся в App.config. Собственно, здесь я напишу о том, как работать с параметрами из конфига.

Добавление в конфиг своей секции

Итак, мы хотим, чтобы в конфиге можно было написать так:
<VisitorSettings hitsPerDay="300" sessionsPerDay="21" duniqsPerDay="15"><Browsers>
  <browser name="chrome" />
  <browser name="iexplore"/>
  <browser name="opera" path="C:\Program Files\Opera\Opera.exe" />
  <browser name="custom" path="C:\Program Files\Safari\Safari.exe" /></Browsers>
</VisitorSettings>
Пишем следующие классы:

Класс для хранения конфигурации браузера

public class Browser : ConfigurationSection
{
  public const string SectionName = "Browsers";
  private const string name = "name";
  private const string path = "path";

  [ConfigurationProperty(name, IsRequired = true)]
  public string Name
  {
    get { return (string)base[name]; }
    set { base[name] = value; }
  }

  [ConfigurationProperty(path, IsRequired = false)]
  public string Path
  {
    get { return (string)base[path]; }
    set { base[path] = value; }
  }

  public string GetBrowserString()
  {
    return String.Format(
      "*{0}{1}{2}",
      Name,
      String.IsNullOrEmpty(Path) ? String.Empty : " ",
      Path
    );
  }
}

Класс для хранения конфигурации списка браузеров

[ConfigurationCollection(typeof(Browser), CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)]
public class BrowserElementCollection : ConfigurationElementCollection
{
  #region Constructor
  static BrowserElementCollection()
  {
    browsers = new ConfigurationPropertyCollection();
  }
  #endregion

  #region Fields
  private static ConfigurationPropertyCollection browsers;
  #endregion

  #region Properties
  protected override ConfigurationPropertyCollection Properties
  {
    get { return browsers; }
  }

  public override ConfigurationElementCollectionType CollectionType
  {
    get { return ConfigurationElementCollectionType.BasicMap; }
  }

  protected override string ElementName
  {
    get
    {
      return "browser";
    }
  }
  #endregion

  #region Indexers
  public Browser this[int index]
  {
    get { return (Browser)base.BaseGet(index); }
    set
    {
      if (base.BaseGet(index) != null)
      {
        base.BaseRemoveAt(index);
      }
      base.BaseAdd(index, value);
    }
  }
  #endregion

  #region Overrides
  protected override ConfigurationElement CreateNewElement()
  {
    return new Browser();
  }

  protected override object GetElementKey(ConfigurationElement element)
  {
    return (element as Browser).GetBrowserString();
  }
  #endregion
}

Класс для самой секции конфига:

public class VisitorSettings : ConfigurationSection
{
  static public string SectionName = "VisitorSettings";

  const string hitsPerDay = "hitsPerDay";
  const string duniqsPerDay = "duniqsPerDay";
  const string sessionsPerDay = "sessionsPerDay";
  const string browsers = "Browsers";

  [ConfigurationProperty(hitsPerDay, IsRequired = true)]
  public int HitsPerDay
  {
    get { return (int)base[hitsPerDay]; }
    set { base[hitsPerDay] = value; }
  }

  [ConfigurationProperty(sessionsPerDay, IsRequired = true)]
  public int SessionsPerDay
  {
    get { return (int)base[sessionsPerDay]; }
    set { base[sessionsPerDay] = value; }
  }

  [ConfigurationProperty(duniqsPerDay, IsRequired = true)]
  public int DuniqsPerDay
  {
    get { return (int)base[duniqsPerDay]; }
    set { base[duniqsPerDay] = value; }
  }
  [ConfigurationProperty(browsers, IsRequired = true)]
  public BrowserElementCollection Browsers
  {
    get { return (BrowserElementCollection)base[browsers]; }
    set { base[browsers] = value; }
  }
}
Готово! Теперь для полного счастья в App.config configSections осталось прописать:
<section name="VisitorSettings" type="Visitor.VisitorSettings, Visitor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

Чтение данных из конфига

Теперь можно писать так:
int uniques = WatcherConfiguration.VisitorSettings.DuniqsPerDay;
int sessions = WatcherConfiguration.VisitorSettings.SessionsPerDay;
int hits = WatcherConfiguration.VisitorSettings.HitsPerDay;
BrowserElementCollection browsers = WatcherConfiguration.VisitorSettings.Browsers;

Редактирование конфига из программы

Пусть теперь у нас есть админка, из которой мы должны иметь возможность добавлять и удалять браузеры. Сначала нужно добавить в класс BrowserElementCollection следующие методы:
#region Методы
public void Add(Browser browser)
{
  base.BaseAdd(browser);
}

public void Remove(string key)
{
  base.BaseRemove(key);
}

public void Remove(Browser browser)
{
  base.BaseRemove(GetElementKey(browser));
}

public void Clear()
{
  base.BaseClear();
}

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

public string GetKey(int index)
{
  return (string)base.BaseGetKey(index);
}
#endregion
Теперь добавлять браузеры мы можем так:
protected void AddBrowser(string name, string path)
{
  Browser browser = new Browser()
  {
    Name = name;
    Path = path;
  };

  WatcherConfiguration.VisitorSettings.Browsers.Add(browser);
  WatcherConfiguration.SaveAll();
}
А удалять - так:
protected void AddBrowser(string name, string path)
{
  WatcherConfiguration.VisitorSettings.Browsers.RemoveAt(index);
  WatcherConfiguration.SaveAll();
}

3 комментария:

Aleksey комментирует...

Спасибки за статью, я как раз искал как мне сделать такую конфиг секцию.

Денис комментирует...

Дарья, подскажите как Вы делаете такие вставки кода с подсветкой синтаксиса?

Анонимный комментирует...

WatcherConfiguration - это что?