Постановка задачи
Требуется создать свою секцию настроек в конфигурационном файле web.config, со структурой более «продвинутой» чем appSettings (то есть нечто большее, чем просто Dictionary). А так же надо реализовать механизм считывания и обновления данных в этой секции.
Как сохранить настройки или выбор стратегии
Снова напомню, что есть серия статей «История одного проекта» (далее ИОП), которая посвящена разработке сайта “музей юмора”. И поэтому, давайте снова поговорим про этот проект, как можно расширить возможности по администрированию этого сайта. Предположим, что лента экспонатов, должна хранить записи за какой-то определенный срок. Например, за одну неделю, то есть семь дней. А если я захочу изменить срок, например на 14 дней? А если я захочу вообще временно отключить удаление записей? А если я хочу временно запретить публикацию экспонатов на ленте через IE-ускоритель? А если… Слишком много «а если»… Надо просто эти параметры где-то хранить с возможностью управления ими непосредственно со страниц сайта. Один из вариантов — файл конфигурации web.config, можно также хранить в базе данных, или, например, в текстовом файле, или сделать другой сайт, на котором сделать web-сервис, который сможет «выдать» всем моим сайта настройки для каждого или общие для всех. Или вообще, всё выложить в облако Azure и платить некоторую сумму в Microsoft… Всё ограничено лишь вашей фантазией. Мы будем говорить про первый вариант – сохранение настроек сайта в файле конфигурации.
Итак, хранение настроек в web.config тоже можно реализовать как минимум двумя способами. Читать/писать данные в файле конфигурации можно:
Возьмем второй вариант. Мне хочется показать пример посложнее, да и структура у меня будет развиваться и совершенствоваться, а потому очень не хочется осознать в какой-то момент, что надо переписывать половину приложения, чтобы реализовать возможность читать/писать данные и настройки в своей секции конфигурации, а не из appSettings.
Начнем с простого. Пусть на данный момент мне требуется такая ветка в файле конфигурации:
1: <SiteSettingsGroup> 2: <SiteSettings> 3: <PagerSize> 4: <EntityName=»Logs»Size=»20″/> 5: <EntityName=»Exhibit»Size=»10″/> 6: <EntityName=»Lenta»Size=»15″/> 7: </PagerSize> 8: <LentaDeleteAfterDays=»17″AllowPostFromShare=»false»/> 9: </SiteSettings> 10: </SiteSettingsGroup>
Если описать вкратце, то SiteSettingsGroup – название группы. SiteSettings – это та самая секция, которую мы будем создавать. PagerSize – это коллекция с настройками размера страницы при отображении в пейджере для определенного типа сущности. Lenta – это дополнительный раздел настроек для ленты анекдотов, а значения атрибутов, итак понятны.
Немного специальных классов
Создадим несколько классов. Для начала – главный класс SiteSettings (также называется и файл .cs). Чтобы все получилось, нужно для начала добавить namespace:
using System.Configuration;
Для начала создадим первый “кирпичик” выбранной структуры – класс LentaElement из указанной выше конфигурации:
1: publicclass LentaElement : ConfigurationElement { 2: 3: [ConfigurationProperty(«DeleteAfterDays», DefaultValue = 7, IsRequired = true)] 4: [IntegerValidator(MinValue = 3, MaxValue = 30, ExcludeRange = false)] 5: publicint DeleteAfterDays { 6: get { 7: return (int)this[«DeleteAfterDays»]; 8: } 9: set { 10: this[«DeleteAfterDays»] = value; 11: } 12: } 13: 14: [ConfigurationProperty(«AllowPostFromShare», DefaultValue = true, IsRequired = true)] 15: publicbool AllowPostFromShare { 16: get { 17: return (bool)this[«AllowPostFromShare»]; 18: } 19: set { 20: this[«AllowPostFromShare»] = value; 21: } 22: } 23: }
Обратите внимание на то, что класс унаследован от ConfigurationElement. Это один из основных базовых классов, которые используются в web.config для разделов. Дальше будет понятнее.
Далее надо бы создать главный раздел для моей секции и уже использовать LentaElement как свойство. Класс я назову SiteSettings:
1: publicclass SiteSettings : ConfigurationSection { 3: [ConfigurationProperty(«Lenta», IsRequired = true)] 4: public LentaElement Lenta { 6: return (LentaElement)this[«Lenta»]; 9: this[«Lenta»] = value;
Между делом или Config-помощник
Для того, чтобы “достучаться” до любого значения любого параметра моей конфигурации, давайте прямо сейчас создадим специальный класс-помощник. Я буду его использовать чтобы протестировать работоспособность конфигурации:
1: publicclass Config { 2: 3: /// <summary> 4: /// скроем конструктор от любопытных программеров 5: /// </summary> 6: internal Config() { } 7: 8: /// <summary> 9: /// наименование раздела конфигурации 10: /// </summary> 11: privateconststring CONFIGGROUPNAME = «SiteSettingsGroup/»; 12: 13: /// <summary> 14: /// наименование секции 15: /// </summary> 16: privateconststring CONFIGSECTIONNAME = «SiteSettings»; 17: 18: /// <summary> 19: /// Чтение раздела конфигурации целиком 20: /// </summary> 21: /// <returns></returns> 22: internalstatic SiteSettings Get() { 23: var config = (SiteSettings)ConfigurationManager
.GetSection(String.Concat(CONFIGGROUPNAME, CONFIGSECTIONNAME)); 24: return config; 25: } 26: }
А теперь пришло время попробовать что получилось. Попробуем прочитать информацию из конфигурации. Я предварительно в файле web.config пока убрал (закомментировал) из своей конфигурации секцию PagerSize. Потому что она еще не реализована, а значить приложение даже не будет пытаться запуститься, а просто вывалится с ошибкой.
В головном контролере в методе Index, я для проверки вставил пару строк, чтобы проверить что конфигурация читается, запустил и…
Отлично! Как раз то, что я и указал в своей конфигурации. Дальше — больше. Я добавил еще несколько классов. Это самое интересное. В раздел SiteSettings я добавил определение класса PagerSizeCollection. Чтобы можно было работать с коллекцией настроек. Далее определил класс PageSizeItemsElement, который и представляет собой одну из строчек в списке PagerSize… Наверное, всё-таки имеет смысл показать весь файл SiteSettings целиком:
1: publicclass SiteSettings : ConfigurationSection 2: { 3: 4: [ConfigurationProperty(«PagerSize»)] 5: public PagerSizeCollection PagerSize 6: { 7: get 8: { 9: return ((PagerSizeCollection)base[«PagerSize»]); 10: } 11: } 12: 13: [ConfigurationProperty(«Lenta», IsRequired = true)] 14: public LentaElement Lenta 15: { 16: get 17: { 18: return (LentaElement)this[«Lenta»]; 19: } 20: set 21: { 22: this[«Lenta»] = value; 23: } 24: } 25: } 26: 27: [ConfigurationCollection(typeof(PageSizeItemsElement), AddItemName = «Entity»)] 28: publicclass PagerSizeCollection : ConfigurationElementCollection 29: { 30: 31: public PageSizeItemsElement this[int index] 32: { 33: get { return (PageSizeItemsElement)BaseGet(index); } 34: } 35: 36: protectedoverride ConfigurationElement CreateNewElement() 37: { 38: returnnew PageSizeItemsElement(); 39: } 40: 41: protectedoverrideobject GetElementKey(ConfigurationElement element) 42: { 43: return ((PageSizeItemsElement)element).Name; 44: } 45: } 46: 47: publicclass PageSizeItemsElement : ConfigurationElement 48: { 49: 50: [ConfigurationProperty(«Size», DefaultValue = 20, IsRequired = true)] 51: [IntegerValidator(MinValue = 5, MaxValue = 100, ExcludeRange = false)] 52: publicint Size 53: { 54: get 55: { 56: return (int)this[«Size»]; 57: } 58: set 59: { 60: this[«Size»] = value; 61: } 62: } 63: 64: [ConfigurationProperty(«Name», DefaultValue = «EntityName», IsRequired = true)] 65: [StringValidator(MinLength = 3, MaxLength = 50,
InvalidCharacters = » ~!@#$%^&*()[]{}/;'»|\»)] 66: public String Name 67: { 68: get 69: { 70: return (String)this[«Name»]; 71: } 72: set 73: { 74: this[«Name»] = value; 75: } 76: } 77: } 78: 79: public class LentaElement : ConfigurationElement 80: { 81: 82: [ConfigurationProperty(«DeleteAfterDays», DefaultValue = 7, IsRequired = true)] 83: [IntegerValidator(MinValue = 3, MaxValue = 30, ExcludeRange = false)] 84: public int DeleteAfterDays 85: { 86: get 87: { 88: return (int)this[«DeleteAfterDays»]; 89: } 90: set 91: { 92: this[«DeleteAfterDays»] = value; 93: } 94: } 95: 96: [ConfigurationProperty(«AllowPostFromShare», DefaultValue = true, IsRequired = true)] 97: public bool AllowPostFromShare 98: { 99: get 100: { 101: return (bool)this[«AllowPostFromShare»]; 102: } 103: set 104: { 105: this[«AllowPostFromShare»] = value; 106: } 107: } 108: }
Чтобы проверить работоспособность проделываю такую же операцию как и в прошлый раз:
Всё работает. Теперь осталось в подключить настройки к системе, то есть начать использовать их. Читается всё замечательно. Попробуем сохранить?
Заключение
В следующей статье я создам форму редактирования настроек (скорее всего это будет knockout.js, то есть значит AJAX).
Подробнее: http://feedproxy.google.com/~r/blogmusor/~3/rSNupmGLoRo/95
Источник: