ASP.NET MVC: Сохраняем настройки сайта в свою секцию файла конфигурации web.config

Что будет в статье?

В предыдущей части были созданы сами настройки и реализовано чтение настроек. В этой предстоит создать форму управления настройками, ajax-сервис, ViewModel на javascript и всё что ещё потребуется.

Сохранение настроек в web.config

Для начал доработаем немного Config-помощник, дописав в него один новый метод, которой будет сохранять настройки:

1: internalstatic Configuring Save(SiteSettings settings) { 2: Configuring success = new Configuring(); 3: try { 4: Configuration cfg = WebConfigurationManager.OpenWebConfiguration(«~»); 5: var group = cfg.SectionGroups[CONFIGGROUPNAME]; 6: SiteSettings section = (SiteSettings)group.Sections[CONFIGSECTIONNAME]; 7: if (section != null) { 8: section.Lenta.AllowPostFromShare = settings.Lenta.AllowPostFromShare; 9: section.Lenta.DeleteAfterDays = settings.Lenta.DeleteAfterDays; 10: section.PagerSize.Clear(); 11: for (int i = 0; i < settings.PagerSize.Count; i++) { 12: section.PagerSize.Add(settings.PagerSize[i]); 13: } 14: cfg.Save(); 15: success.Success = true; 16: } 17: } 18: catch (ConfigurationErrorsException error) { 19: success.ConfigException = error; 20: } 21: return success; 22: }

Рисуем форму редактирования

В панели управления администратора я сделал ссылку на представление Settings.cshtml. И вот так, не сложно, наполнил это представление html-разметкой:

1: <div class=»clear»> 2: <div class=»left» style=»width: 49%»> 3: <h4>Лента</h4> 4: <div class=»editor-label»> 5: <label for=»DeleteAfterDays»>Очищать старее чем, дни:</label> 6: </div> 7: <div class=»editor-field»> 8: <input type=»text» id=»DeleteAfterDays»value=»» /> 9: </div> 10: <div class=»editor-label»> 11: <input type=»checkbox» id=»AllowPostFromShare» /> 12: Разрешить публикацию через ускоритель 13: </div> 14: </div> 15: <div class=»left» style=»width: 49%»> 16: <h4>Пользовательский интерфейс</h4> 17: <h6>Настройки пейджера для сущностей</h6> 18: <div></div> 19: <button>+</button> 20: </div> 21: </div> 22: 23: <div class=»clear»></div> 24: <p> 25: <button>Сохранить все</button> 26: </p>

И раз уж я решил реализовать задуманное с использованием фреймворка Knockout.js, то далее это представление наполнится атрибутами привязки (data-bind). А пока надо подключить требуемые скрипты к этому представлению. Хочу заметить, что это пока не полный список.

1: @section scripts{ 2: <scriptsrc=»@Url.Content(«~/scripts/knockout-2.1.0.js»)»></script> 3: <script src=»@Url.Content(«~/scripts/knockout.validation.js»)»></script> 4: }

Лирическое отступление

Я набросал небольшой Nuget-пакет, который при установки создает папку Js и помещает туда пока один единственный файл site.core.js (читателям моего блога название должно быть знакомо). Далее я постараюсь наполнить контролами и различными полезными штуками этот пакет, по мере написания сайтов. Это хороший старт для вашего фреймворка на JavaScript для всего сайта. Файл содержит обертку на jQuery методы getJSON и postJSON. Я установил себе в проект этот пакет:

PM> Install-Package JsSite
Successfully installed ‘JsSite 0.1.0’.
Successfully added ‘JsSite 0.1.0’ to Calabonga.Mvc.Humor.

PM>

Пакеты и скрипты установлены. Давай подготовим серверную часть.

Создаем новый контролер

Название для контролера AjaxController говорит само за себя. Этот контролер будет обслуживать весь сайт. Но пока в нем будет только пара методов. Вот первый, он читает данные из конфигурации:

1: public JsonResult LoadSettings() { 2: SiteSettings config = Config.Get(); 3: var jsonConfig = new SiteSettingsJson(); 4: jsonConfig.Lenta.AllowPostFromShare = config.Lenta.AllowPostFromShare; 5: jsonConfig.Lenta.DeleteAfterDays = config.Lenta.DeleteAfterDays; 6: for (int i = 0; i < config.PagerSize.Count; i++) { 7: jsonConfig.PagerSize.Add(new PagerSizeItem { 8: Name = config.PagerSize[i].Name, 9: Size = config.PagerSize[i].Size 10: }); 11: } 12: return Json(jsonConfig, JsonRequestBehavior.AllowGet); 13: }

Следует остановиться на минутку и описать казус, который у меня приключился. В строке 2 я получаю объект и при попытке его отправить через JsonResult в строке 12 выдавалась ошибка сериализации объекта SiteSettings. Сам по себе объект простой, но его предки (вспомните от чего он унаследован) упорно не хотели проходить сериализацию. Пришлось сделать простой прокси-класс SiteSettingsJson, и, наполняя его данными передавать на форму. Класс настолько прост, что я даже его приводить не буду, да?

Время для Js-сервиса

Новый файл в папке Js я назвал site.services.js. Вот его содержимое:

1: /// <reference path=»site.core.js» /> 2: /// <reference path=»../Scripts/jquery-1.8.1.js» /> 3: /// <reference path=»../Scripts/knockout-2.1.0.debug.js» /> 4: 5: (function (site) { 6: 7: «use strict»; 8: 9: site.services.settings = { 10: load: function (callback) { 11: site.fw.ajaxService.getJson(«LoadSettings», {}, callback); 12: }, 13: save: function (jsonData, callback) { 14: site.fw.ajaxService.postJson(«SaveSettings», jsonData, callback); 15: } 16: } 17: 18: })(site);

Этот сервис использует обертку на ajax, которую я получил вместе с JsSite-пакетом. Как вы видите есть уже и второй метод, который будет сохранять данные, но его я пока не писал в AjaxController’e, займусь им позже.

Основной ViewModel на JavaScript? Легко!

Для начала нужно прочитать настройки и отобразить их при открытии страницы. Для этого я создал ViewModel страницы Settings.cshtml, который “умеет” загружать настройки. Файл я назвал site.vm.settings.js положил его в папку Js:

1: /// <reference path=»site.core.js» /> 2: /// <reference path=»site.services.js» /> 3: /// <reference path=»../Scripts/jquery-1.8.1.js» /> 4: /// <reference path=»../Scripts/knockout.mapping-latest.debug.js» /> 5: /// <reference path=»../Scripts/knockout-2.1.0.debug.js» /> 6: 7: (function (site) { 8: 9: «use strict»; 10: 11: site.vm.settings = function () { 12: var 13: //статус работы сервиса 14: isbusy = ko.observable(false), 15: 16: // конфигурация 17: config = ko.observable({ 18: «Lenta»: ko.observable({ 19: «DeleteAfterDays»: ko.observable(), 20: «AllowPostFromShare»: ko.observable(true) 21: }), 22: «PagerSize»: ko.observableArray() 23: }), 24: 25: // PagerSize: название 26: newName = ko.observable(«Entity»), 27: 28: // PagerSize: размер страниц 29: newSize = ko.observable(0), 30: 31: // метод загрузки конфигурации 32: load = function () { 33: isbusy(true); 34: site.services.settings.load(function (json) { 35: isbusy(false); 36: ko.mapping.fromJS(json.Config, {}, config); 37: }); 38: }, 39: 40: // сохранение настроек 41: save = function () { 42: isbusy(true); 43: var jsonData = ko.toJSON(config); 44: site.services.settings.save(jsonData, function (json) { 45: isbusy(false); 46: alert(json) 47: }) 48: }, 49: 50: // добавдение объекта в список PagerSize 51: add = function () { 52: config().PagerSize.push(new PagerSize(newName(), newSize())); 53: newName(«Entity»); newSize(10); 54: }, 55: 56: // удаление объекта из списка PagerSize 57: remove = function (item) { 58: config().PagerSize.remove(item); 59: }; 60: 61: load(); 62: 63: return { 64: config: config, 65: isbusy: isbusy, 66: remove: remove, 67: add: add, 68: newName: newName, 69: newSize: newSize, 70: save:save 71: } 72: }(); 73: 74: })(site);

Не думаю, что нужно подробно останавливаться на распечатке. Тем более, что я постарался с комментариями.

Представление Settings.cshtml

Теперь надо показать html-код разметки этого самого представления Settings.cshtml, потому что я кое-что добавил и “нашпиговал” атрибутами привязки. Приведу этот код тоже целиком:

1: @{ 2: ViewBag.Title = «Настройки системы»; 3: Layout = «~/Views/Shared/_LayoutMain.cshtml»; 4: } 5: 6: <h2>Настройки системы</h2> 7: <divdata-bind=»ifnot: isbusy»> 8: <divclass=»clear»> 9: <divclass=»left»style=»width: 49%»> 10: <h4>Лента</h4> 11: <divclass=»editor-label»> 12: <labelfor=»DeleteAfterDays»>Очищать старее чем, дни:</label> 13: </div> 14: <divclass=»editor-field»> 15: <inputtype=»text»id=»DeleteAfterDays» 16: data-bind=»value: config().Lenta().DeleteAfterDays»/> 17: </div> 18: <divclass=»editor-label»> 19: <inputtype=»checkbox»id=»AllowPostFromShare» 20: data-bind=»checked: config().Lenta().AllowPostFromShare»/> 21: Разрешить публикацию через ускоритель 22: </div> 23: </div> 24: <divclass=»left»style=»width: 49%»> 25: <h4>Пользовательский интерфейс</h4> 26: <h6>Настройки пейджера для сущностей</h6> 27: <divdata-bind=»foreach: config().PagerSize»> 28: <p> 29: <b><spandata-bind=»text: Name»></span></b>&nbsp;на одной странице <b> 30: <spandata-bind=»text: Size»></span></b> 31: <buttondata-bind=»click: $parent.remove»>х</button> 32: </p> 33: </div> 34: Название класса сущности:<br/> 35: <inputtype=»text»data-bind=»value: newName»/><br/> 36: Количество объектов на странице:<br/> 37: <inputtype=»text»data-bind=»value: newSize»/><br/> 38: <buttondata-bind=»click: add»>Добавить новую</button> 39: </div> 40: </div> 41: 42: <divclass=»clear»></div> 43: <p> 44: <buttondata-bind=»click: save»>Сохранить все</button> 45: </p> 46: </div> 47: @section scripts{ 48: <scriptsrc=»@Url.Content(«~/scripts/knockout-2.1.0.js»)»></script> 49: <script src=»@Url.Content(«~/scripts/knockout.validation.js»)»></script> 50: <script src=»@Url.Content(«~/scripts/knockout.mapping-latest.js»)»></script> 51: <script src=»@Url.Content(«~/js/site.core.js»)»></script> 52: <script src=»@Url.Content(«~/js/site.services.js»)»></script> 53: <script src=»@Url.Content(«~/js/site.vm.settings.js»)»></script> 54: <script> 55: $(function () { 56: ko.applyBindings(site.vm.settings); 57: }); 58: </script> 59: }

Ну, и как это выглядит, чтобы уж совсем всё было наглядно:

Слева я значение 17 поменяю на 15, а  правом списке к уже существующим: Logs, Exhibit, Lenta добавил еще одну сущность Comment и теперь в режиме отладки хочу проверить, приходят ли данный в AjaxController. А-а-а-а-а вот они-и!

Осталось только “прикрутить” валидацию», но это пусть будет уже вашим домашним заданием, тем более, что об этом уже был разговор. А еще надо написать метод сохранения данных. Так как у меня появился прокси-класс для настроек, то теперь я могу использовать его как входящие данные для метода сохранения в Config-помощнике. Итак, представлю второй метод Config-помощника:

1: internalstatic Configuring Save(SiteSettingsJson settings) 2: { 3: Configuring success = new Configuring(); 4: try 5: { 6: Configuration cfg = WebConfigurationManager.OpenWebConfiguration(«~»); 7: var group = cfg.SectionGroups[CONFIGGROUPNAME]; 8: SiteSettings section = (SiteSettings)group.Sections[CONFIGSECTIONNAME]; 9: if (section != null) 10: { 11: section.Lenta.AllowPostFromShare = settings.Lenta.AllowPostFromShare; 12: section.Lenta.DeleteAfterDays = settings.Lenta.DeleteAfterDays; 13: section.PagerSize.Clear(); 14: for (int i = 0; i < settings.PagerSize.Count; i++) 15: { 16: section.PagerSize.Add(new PageSizeItemsElement() 17: { 18: Name = settings.PagerSize[i].Name, 19: Size = settings.PagerSize[i].Size 20: }); 21: } 22: cfg.Save(); 23: success.Success = true; 24: } 25: } 26: catch (ConfigurationErrorsException error) 27: { 28: success.ConfigException = error; 29: } 30: return success; 31: }

Вот еще маленький класс упомянутый в предыдущем листинге, для полноты картины:

1: publicclass Configuring 2: { 3: publicbool Success { get; set; } 4: 5: public ConfigurationErrorsException ConfigException { get; set; } 6: }

И, наконец, завершим начатое. Вот конечный вариант второго метода AjaxController’а, который сохраняет данные: 1: [HttpPost] 2: public JsonResult SaveSettings(SiteSettingsJson config) { 3: Response.CacheControl = «no-cache»; 4:   5: string message=string.Empty; 6:   7: if (ModelState.IsValid) 8: { 9: Config.Save(config); 10: message = «Настройки успешно сохранены»; 11: } 12: else { message = «Неверные данные в конфигурации»; } 13: return Json(message); 14: }

Заключение

Данные читаются, изменяются, сохраняются – значит поставленная цель достигнута и моя миссия завершена. Вас же я прошу писать комментарии.

Да прибудет с вами сила!

Подробнее: http://feedproxy.google.com/~r/blogmusor/~3/9Iz8lWcbfbo/96

Источник: lred.ru

Оцените статью
новости для мужчин