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> на одной странице <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
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2024-11-26 » Капитан грузового судна, или Как начать использовать Docker в своих проектах
- 2024-11-26 » Обеспечение безопасности ваших веб-приложений с помощью PHP OOP и PDO
- 2024-11-22 » Ошибки в Яндекс Вебмастере: как найти и исправить
- 2024-11-22 » Ошибки в Яндекс Вебмастере: как найти и исправить
- 2024-11-15 » Перенос сайта на WordPress с одного домена на другой
- 2024-11-08 » OSPanel 6: быстрый старт
- 2024-11-08 » Как установить PhpMyAdmin в Open Server Panel
- 2024-09-30 » Как быстро запустить Laravel на Windows
- 2024-09-25 » Next.js
- 2024-09-05 » OpenAI рассказал, как запретить ChatGPT использовать содержимое сайта для обучения
- 2024-08-28 » Чек-лист: как увеличить конверсию интернет-магазина на примере спортпита
- 2024-08-01 » WebSocket
- 2024-07-26 » Интеграция с Яндекс Еда
- 2024-07-26 » Интеграция с Эквайринг
- 2024-07-26 » Интеграция с СДЕК
- 2024-07-26 » Интеграция с Битрикс-24
- 2024-07-26 » Интеграция с Travelline
- 2024-07-26 » Интеграция с Iiko
- 2024-07-26 » Интеграция с Delivery Club
- 2024-07-26 » Интеграция с CRM
- 2024-07-26 » Интеграция с 1C-Бухгалтерия
- 2024-07-24 » Что такое сторителлинг: техники и примеры
- 2024-07-17 » Ошибка 404: что это такое и как ее использовать для бизнеса
- 2024-07-03 » Размещайте прайс-листы на FarPost.ru и продавайте товары быстро и выгодно
- 2024-07-01 » Профилирование кода в PHP
- 2024-06-28 » Изучаем ABC/XYZ-анализ: что это такое и какие решения с помощью него принимают
- 2024-06-17 » Зачем вам знать потребности клиента
- 2024-06-11 » Что нового в работе Яндекс Метрики: полный обзор обновления
- 2024-06-11 » Поведенческие факторы ранжирования в Яндексе
- 2024-06-11 » Скорость загрузки сайта: почему это важно и как влияет на ранжирование
Не делай другим то, что ты хотел бы, чтобы они делали для тебя. У вас могут быть разные вкусы Шоу Джордж Бернард - (1856-1950) - английский писатель. В своем творчестве ниспровергал догматизм и предвзятость, традиционность представлений |
Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!
Как мы работаем
Заявка
Позвоните или оставьте заявку на сайте.
Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!
Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.
Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.
Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.