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:  }

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

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

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

96-savesettings

Осталось только “прикрутить” валидацию", но это пусть будет уже вашим домашним заданием, тем более, что об этом уже был разговор. А еще надо написать метод сохранения данных. Так как у меня появился прокси-класс для настроек, то теперь я могу использовать его как входящие данные для метода сохранения в 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

Читать комменты и комментировать

Добавить комментарий / отзыв



Защитный код
Обновить

ASP.NET MVC: Сохраняем настройки сайта в свою секцию файла конфигурации web.config | | 2012-09-24 00:54:03 | | Программирование | | Что будет в статье?В предыдущей части были созданы сами настройки и реализовано чтение настроек. В этой предстоит создать форму управления настройками, ajax-сервис, ViewModel на javascript и всё что | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Поделиться с друзьями: