Веб-разработка на 1Script. Глава 2

Программирование - Практика программирования

Продолжение учебника по веб-разработке с помощью фреймворка Oscript.Web. Структура приложения, основные объекты, URL-маршрутизация, универсальная консоль серверов 1С.

Краткое содержание предыдущих серий

Я веду разработку веб-фреймворка, который позволит писать веб-приложения на языке 1С. Причем я имею в виду не только и не столько сайты. Речь идет именно о приложениях, у которых есть веб-интерфейс и некоторая полезная функциональность. Веб-сайты являются разновидностью веб-приложений.

Попутно, я пишу данный цикл статей, которые совокупно можно считать книгой-учебником по разрабатываемому Фреймворку. И, поскольку, фреймворк находится в разработке – этот цикл статей еще и своего рода блог или репортаж с мест событий. Рабочее название проекта Oscript.Web или OSP.NET

В прошлой главе мы настроили окружение разработчика, установили необходимые инструменты, а также создали каркас будущего приложения. Приложением у нас является универсальная консоль администрирования серверов 1С, которая не требует постоянной перерегистрации COM-объектов для подключения к серверам 1С разных версий. Эта консоль получила название «Odminus». Ее исходный код открыт, и по мере накопления опыта в использовании фреймворка OSP.NET, сообщество сможет ее развивать самостоятельно. Итак, продолжим.

Проектирование

После написания первой статьи я сел и стал думать, как именно должно выглядеть будущее приложение. Оказалось, что каркас интерфейса, который был создан в прошлой статье – не совсем отвечает тому, какую структуру должна иметь консоль администрирования серверов 1С.

Я большой фанат книги А. Купера «Психбольница в руках пациентов». Легендарная вещь, раскрывающая глаза на проектирование систем, которыми напрямую должен пользоваться homo sapiens. Если вы еще не читали – прямо срочно бежим на торренты в магазин и приобретаем. Очень советую. Если очень упростить, то Купер говорит, что приложение надо проектировать с интерфейса. С того, как именно с приложением будет взаимодействовать человек. И именно удобство для человека должно определить дальнейшую технологическую архитектуру системы. Те части, с которыми человек не взаимодействует – можно проектировать любым удобным способом.

Так вот, оказалось, что веб-приложение тоже удобнее всего проектировать с того, что именно видит человек. Более того, наиболее важным и сложным для меня оказалось продумывание навигации по приложению. Какие именно гиперссылки в какую часть системы будут вести. Время гиперссылок web 1.0 прошло. Километровые параметры запроса в url – это уже не клево, и используется только в особых случаях. Мы все привыкли видеть адресацию вида /users/add, clients/pupkin/edit и /books/purchase/1c-radchenko и подобные. Адреса вида /users.php?action=delete&id=00001 это уже прошлый век.

Как мы помним из прошлой главы, в MVC применяется маршрутизация в разрезе Контроллеров и Действий. Причем Контроллер и Действие получаются из URL, запрошенного пользователем. Правила, по которому URL превращается в Контроллер и Действие называется Маршрутом.

Так вот, попытка разложить модель данных консоли администрирования 1С на Контроллеры и Действия, да еще и так, чтобы это было наглядно для homo sapiens (по заветам Купера), привела меня к мысли о том, что типовая схема маршрутизации /controller=Ноme/action=Index/id? не всегда хороша.

Схема взаимодействия

Итак, что из главного должен видеть 1с-одмин, который пользуется консолью? Если отбросить модные дашборды, которые всегда можно прикрутить позже – одмин должен видеть следующее:

  • Какие центральные сервера у него есть
  • Внутри сервера видеть кластеры
  • Внутри кластеров – базы, сеансы и все остальное

Далее, поскольку все администрирование с помощью штатного приложения rac так или иначе требует указания идентификатора кластера, то получается следующая схема маршрутов:

  • Выбор машины с агентом кластера
    • Контроллер agents и его CRUD операции (create/read/update/delete)
    • Типовая схема маршрута контроллер/действие/идентификатор подходит хорошо
  • Выбор кластера внутри агента
    • Пусть будет адрес вида /agents/clusters для списка кластеров
    • Пусть будет адрес /cluster/overview/id. Причем id кластера это GUID, поскольку именно его возвращает утилита rac и именно с этим GUID мы работаем, управляя кластером через нее.
    • Типовая схема тоже подходит худо-бедно
  • Операции с объектами кластера
    • Все CRUD вещи над каждой из сущностей удобнее завернуть в отдельный контроллер для каждой из них. Чтобы были контроллеры /databases /sessions /servers и т.п.
    • Все они потребуют помимо id сущности еще и UUID кластера. Поэтому родился вот такой вариант адреса: /database/create?cluster=UUID или /database/ZUP/sessions?cluster=UUD

Также получилось, что главная страница (которая по умолчанию маршрутизируется в home/index), во-первых, не очень-то и нужна, а во-вторых – должна иметь другой интерфейс, без боковой панели. Боковую панель удобно выводить уже для манипуляций кластером и его объектами.

Главной же страницей, исходя из вышесказанного, должна быть страница контроллера agents.

Теперь, когда стало понятно, чего мы хотим добиться, можно перейти непосредственно к изучению веб-приложения.

Устройство веб-приложения

Для продолжения нам потребуется свежая версия движка Oscript.Web, которую можно скачать по адресу https://github.com/EvilBeaver/OneScript.Web/releases/tag/v0.2-alpha. Распакуйте архив в удобное место. Желательно, чтобы путь к этому месту был коротким. D:\osweb отлично подойдет.

Откроем Visual Studio Code и в нем откроем папку с последней версией исходников сего учебника. Свежие исходники нужно получить из git (https://github.com/EvilBeaver/osp-articles) операцией git pull. Наш пример кода находится в папке chapter-02.

Начало работы системы

Как и в привычном нам 1С-приложении, выполнение программы начинается с метода ПриНачалеРаботыСистемы, расположенного в модуле приложения.

Модуль приложения - это файл main.os, расположенный в корне каталога исходников src. Мы бегло рассмотрели его в прошлой главе.

Процедура ПриНачалеРаботыСистемы отвечает за настройку веб-приложения. В ней выполняются все необходимые инициализации, относящиеся к приложению в целом. В отличие от 1С, в которой ПриНачалеРаботыСистемы вызывается на клиенте и относится к клиентской сессии, в веб-движке 1script эта процедура вызывается один раз, при старте сервера приложений. Все переменные, объявленные в модуле приложения являются глобальными не для сессии, а для приложения в целом. Все пользовательские сеансы делят между собой состояние, хранимое в глобальных переменных. Поэтому не стоит хранить там данные, которые могут изменяться клиентскими сессиями, во избежание непредсказуемых результатов многопоточного доступа к одним и тем же данным.

Сейчас в этой процедуре находятся 2 вызова:

Процедура ПриНачалеРаботыСистемы()

       ИспользоватьСтатическиеФайлы();
       ИспользоватьМаршруты();

КонецПроцедуры

В модуле приложения доступны так называемые pipeline-методы. Эти методы отвечают за то, как веб-запрос будет проходить по внутренностям веб-приложения. Каждый такой вызов метода отвечает за добавление в конвейер обработки определенной логики. В приведенном примере в конвейер добавляется обработчик статических файлов. Если веб-запрос запрашивает файл, который реально существует на диске, то клиенту будет сразу возвращен этот файл. Если же путь веб-запроса не указывает на реальный файл, то будет переход к следующему методу ИспользоватьМаршруты. И тогда в игру вступит упомянутая ранее маршрутизация и деление на Контроллеры, Действия и прочее.

Если поменять эти методы местами, то будет обратная логика. Сначала всегда будут обрабатываться маршруты, и только если они никуда не привели (не совпали ни с одним шаблоном) – то будет выполнена попытка посмотреть на файловую систему и попробовать обслужить запрос файлом с диска.

Пример: есть обращение от клиента по адресу «/catalog/books/radchenko.zip» Все, что сервер имеет на входе – это данная строка. Что нужно отдать клиенту? Возможно это прямой путь к файлу на сервере, а возможно это обращение к некоей бизнес логике, которая достанет из базы данных нужный архив и вышлет его клиенту. Как приложение должно реагировать на этот запрос? Методы конвейера как раз и позволяют определить порядок обработки запроса. В нашем случае – сначала будет выполнен поиск файла на диске, а потом (если его не оказалось) попытка передачи запроса в подсистему маршрутизации контроллеров.

Если убрать метод ИспользоватьСтатическиеФайлы(), то файлы с диска вообще не будут обслуживаться. А если убрать метод ИспользоватьМаршруты(), то вообще не будет работать подсистема MVC – только обращение к реальным файлам.

Помимо упомянутых методов в текущей версии существует еще метод ИспользоватьСессии(). Он отвечает за хранение/восстановление пользовательских сеансов на основании заголовков Cookies.

Если хранение состояния сессии в приложении не требуется, то эта функциональность просто не добавляется в конвейер.

Вернемся к Консоли Серверов

Если посмотреть еще раз на принятую схему взаимодействия нашего приложения, то становится ясно, что места для странички Home не находится. Более того, на главной странице есть боковая панель, которую особо нечем наполнить. Наиболее логично оставить в качестве главной страницы список агентов (URL /agents) и убрать боковую панель. А вот когда мы переходим к работе внутри кластера, вот тогда боковая панель появится.

Раскладки

Как мы уже говорили, в разметке сайта используется так называемая «страница раскладки». Каркас главной разметки, который определяет относительное расположение блоков содержания. Напомню, что раскладки хранятся в папке views/shared и начинаются с подчеркивания.

Мы хотим, чтобы страница со списком агентов кластера открывалась без боковой панели (поскольку в ней нечего толком разместить). Создадим рядом с основной раскладкой файл _noSidebarLayout.cshtml следующего содержания:

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" href="/redirect.php?url=aHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvc2VtYW50aWMtdWkvMi4yLjEzL3NlbWFudGljLm1pbi5jc3M="/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.js"></script>
</head>
<body>
    <!-- top menu -->
    <div class="ui inverted huge borderless fluid menu">
      <a class="header item">Odminus</a>
      <div class="right menu">
        <a class="item">Настройки</a>
        <a class="item">Помощь</a>
      </div>
    </div>
    <div class="ui container">
        @RenderBody()
    </div>
</body>

Очень простая разметка, по сути заголовок страницы и место под содержимое, которое будет выведено в месте вызова RenderBody()

Далее, зайдем в файл /views/agents/Item.cshtml и в самом начале файла добавим переопределение раскладки:

@{
    Layout = "_noSidebarLayout"
}

Ту же операцию повторим для файла /views/agents/Index.cshtml

Код внутри скобок – это выражение Razor. Мы остановимся на нем несколько позже. Смысл данного кода таков, что мы не ходим использовать раскладку по-умолчанию, а хотим для данной страницы применять другую. Кстати, если интересно, а как система узнает – какая именно раскладка является «раскладкой по умолчанию» - загляните в файл _ViewStart.cshtml. Можно, кстати, вообще отменить использование раскладок и полностью сверстать страницу с нуля. Тогда нужно свойству Layout присвоить значение null. Пока не стоит сильно вдаваться в детали верстки страниц Razor, я думаю, ему нужно будет посвятить отдельную главу. Кроме того, это далеко не единственный способ верстки фронтенда в современном мире. Razor прост, понятен, он ближе к чистому HTML чем магические JS-фреймворки React/Angular и иже с ними.

Фронтенду для 1С-ников посвящены отдельные научно-исследовательские работы в нашей секретно-подпольной лаборатории «Очумелые ручки». Пока же я полагаю, что Razor выучивается достаточно просто для того, чтобы на него не сильно отвлекаться при изучении нашей темы.

Итак, мы переопределили свойство Layout и назначили новую раскладку.  Теперь, при переходе на адрес /agents мы будем видеть, что расположение контента внутри страницы поменялось и соответствует новой раскладке.

Боковая панель на странице агентов теперь отсутствует, т.к. применена другая раскладка страницы.

Переопределение маршрутов

Как уже говорилось выше, мы пришли к выводу, что страничка home нам пока не нужна. И главной страницей является страница /agents. Однако, схема маршрутизации, которая нами применяется, использует в качестве контроллера по умолчанию контроллер home. Нам нужно объяснить системе, что мы хотим применять нестандартную схему маршрутизации. Большинство веб-приложений имеют несколько разных схем для разных участков приложения. По мере развития приложения нам, скорее всего, придется добавлять новые и новые варианты маршрутизации URL.

Прочтите, пожалуйста, внимательно следующий раздел.

Маршрутизация в подробностях

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

Если вы посмотрите на устройство HTTP-сервисов в 1С, то вы увидите, что там тоже есть система маршрутизации и задание сегментов URL. Здесь будет нечто похожее, только, на мой взгляд, несколько более лаконичное.

Вбивать вручную каждый адрес, который распознает приложение – занятие неблагодарное. Поэтому, обычно задают некий шаблон адреса, который потом сопоставляется с запрошенной страницей. Вот простой пример: http://someserver.com:2541/Admin/Login

Этот URL можно разложить на сегменты: части адреса, которые следуют после имени сервера и порта и разделены символом «/». В данном случае у нас в адресе 2 сегмента: Admin и Login. Схема маршрутизации, применяемая по умолчанию, сооотнесет первый сегмент с именем Контроллера, а второй – с методом Действия в данном Контроллере.

Шаблон URL, соответствующий данному адресу, будет следующим: {controller}/{action}

При обработке входящего HTTP-запроса система маршрутизации сопоставит запрошенный адрес Admin/Login с шаблоном и присвоит переменным сегментов controller и action значения Admin и Login соответственно. Как вы, наверное, догадались, переменные сегментов объявляются с помощью фигурных скобок.

Обычно приложение обходит список имеющихся шаблонов маршрутизации и сопоставляет с каждым из них запрошенный URL. Если не вдаваться в детали, то сопоставление выполняется по совпадению количества сегментов. Любой адрес, состоящий из двух сегментов будет совпадать с нашим шаблоном {controller}/{action}

Адрес /Admin не совпадет – сегментов слишком мало. Адрес /Admin/Login/NewUser тоже не совпадет, сегментов слишком много.

Если же количество сегментов совпадает, то значения сегментных переменных извлекаются из адреса и присваиваются.

Регистрация маршрутов в приложении

Выше была описана функция ИспользоватьМаршруты и ее роль в конвейере обработки HTTP-запроса.

В эту функцию можно передать строкой имя метода-обработчика, который будет выполнять настройку маршрутов.

Почему так сложно? Приложение может вообще не использовать маршруты в конвейере обработки и отдавать, скажем, только файлы с диска. Обработчиков в конвейере может быть достаточно много и текущий вариант, показался наиболее простым способом параметризации шага конвейера. В метод «шага» передается имя обработчика, который может тем или иным образом настроить шаг конвейера.

Продолжим: создадим в модуле приложения (main.os) следующую процедуру:

Процедура ОпределениеМаршрутов(КоллекцияМаршрутов)

КонецПроцедуры

Затем, в процедуре ПриНачалеРаботыСистемы передайте имя «ОпределениеМаршрутов» в качестве строкового параметра метода ИспользоватьМаршруты:

Процедура ПриНачалеРаботыСистемы()
	ИспользоватьСтатическиеФайлы();
	ИспользоватьМаршруты("ОпределениеМаршрутов");
КонецПроцедуры

Параметром обработчика ОпределениеМаршрутов является специальная коллекция «КоллекцияМаршрутов», которая позволяет описать возможные шаблоны URL для нашего приложения.

Например, приведенный маршрут {controller}/{action} регистрируется вот так:

КоллекцияМаршрутов.Добавить("Основной","{controller}/{action}");

 

Значения по умолчанию и необязательные сегменты

Обычно, если не удалось сопоставить URL ни одному из шаблонов в коллекции маршрутов, то клиенту отдается ответ 404 «Страница не найдена».

Поэтому, если зайти просто на адрес нашего сайта, то сегментов после имени сервера не будет. А значит, маршрутизация не найдет маршрута для "нуля" сегментов, и запрос выдаст 404. Разумеется, это неудобно, поэтому, шаблоны маршрутов поддерживают значения по умолчанию. Значение по умолчанию применяется, когда URL не содержит сегмента, но в шаблоне задано значение, которое можно подставить в качестве значения этого сегмента.

На протяжении данной книги я уже упоминал шаблоны, применяющие значения по умолчанию. В частности, если не передать в метод ИспользоватьМаршруты никаких параметров, то будет использован шаблон URL по умолчанию, который выглядит вот так:

{controller=Home}/{action=Index}/{id?}

Значения по умолчанию присвоены внутри объявления сегментных переменных. Если сегмент в URL будет отсутствовать, то система подставит вместо него значение по умолчанию и проведет маршрутизацию. Именно поэтому адреса «/», «/Home» и «/Home/Index» идентичны.

Обратите также внимание на необязательный сегмент id. Необязательный сегмент помечается знаком вопроса. У него нет значения по умолчанию (которое позволяет опустить 3 сегмент), он просто может отсутствовать в запрошенном URL.

Статичные сегменты

Шаблон адреса не обязательно должен содержать только переменные. Допускается указание и статичных строк.

  • /Public/Documents/{controller}/{action=Index} – часть сегментов статична
  • /Library/Page{number}/{user} – второй сегмент включает в себя переменную. Он совпадет с адресом Page1, Page2 и PageАБЫРВАЛГ. Значение number не будет включать в себя префикс Page

Значения по умолчанию вне шаблона

Не всегда возможно указать контроллер и действие внутри шаблона URL. Обратите внимание на последний пример. В нем нет «подсказки» для системы маршрутизации. Она не узнает в какой контроллер отправить запрос на обработку. Для таких случаев применяется 3-й параметр метода «Добавить» в коллекции маршрутов. В качестве 3 параметра можно передать соответствие со значениями по умолчанию для каждой переменной в шаблоне маршрута.

Умолчания = Новый Соответствие;
Умолчания.Вставить("controller","LibArchive");
Умолчания.Вставить("action","Extract");
Умолчания.Вставить("number","1");

КоллекцияМаршрутов.Добавить("Основной",
     "Library/Page{number}/{user}",
      Умолчания);

Особенности обработки маршрутов

Маршруты обрабатываются в порядке из добавления в коллекцию маршрутов. Поэтому, наиболее «общие» шаблоны нужно располагать в конце списка, иначе они «съедят» любой URL и маршрутизация не дойдет до более специфичных маршрутов.

Переменные controller и action единственные «предопределенные» переменные, о которых знает система и использует для маршрутизации. Остальные переменные никак не обрабатываются и просто доступны для вашего кода в коллекции ЗначенияМаршрута при обработке запроса. Вы можете сами решать – что с ними делать.

Помимо «знака вопроса», которым обозначается необязательный сегмент, есть еще один спецсимвол – «звездочка». Переменная, начинающаяся со звездочки «захватывает» вообще все, что встречается в URL в качестве своего значения. Вот шаблон «со звездочкой»:

«{controller=home}/{action=index}/{id?}/{*anything}»

Этот шаблон будет совпадать вообще с любым URL, из любого числа сегментов:

/

controller = home; action = index; id = Неопределено; anything = Неопределено

/agents/delete

controller = agents; action = delete; id = Неопределено; anything = Неопределено

/agents/delete/0001/Blabla/orBloBlo

controller = agents; action = delete; id = 0001; anything = Blabla/orBloBlo

В качестве значения «переменной со звездочкой» захвачен весь «хвост» адреса, что бы в нем ни находилось.

Ограничения на маршруты

Помните пример шаблона /Library/Page{number}/{user}, который совпадал с адресами Page1, Page2 и PageАБЫРВАЛГ?

Чтобы такого не происходило, можно задавать некоторые ограничения на совпадающие значения. В данном случае, мы можем задать, чтобы в качестве number нам передавалось только число:

/Library/Page{number:int}/{user}

Теперь, данный шаблон будет совпадать только с адресами, у которых часть {number} будет являться целым числом.

Вот несколько часто применяемых ограничений:

alpha

Регистронезависимая строка символов

Разрешено ABC и abc, но не разрешено ab123

bool

true и false

 

datetime

Строка, которую можно распарсить в дату-время.

Поддерживается много различных форматов, см. документацию .NET

range(min,max)

Диапазон  значений между min и max (включительно)

 

regex(expr)

Регулярное выражение

URL совпадает, если сегмент совпадает с выражением expr

Остальные варианты ограничений можно найти в документации ASP.NET MVC

Устройство контроллеров

Итак, мы поняли, как работают маршруты. Укажем в методе «ОпределениеМаршрутов», что страницей по-умолчанию у нас является agents.

Процедура ОпределениеМаршрутов(КоллекцияМаршрутов)
	КоллекцияМаршрутов.Добавить("Основной","{controller=agents}/{action=Index}/{id?}");
КонецПроцедуры

Теперь, давайте обратимся к коду контроллера agents и посмотрим подробнее, как он работает:

Методы «Действия»

Как мы помним из предыдущей главы, каждый экспортный метод контроллера является методом «Действия», который вызывается системой маршрутизации. Для контроллера agents это методы Index, Add, Edit и Delete.

Как правило, метод действия – это функция, которая возвращает один из специальных объектов группы РезультатДействия. Результат действия, это объект, который отвечает за формирование ответа, отправляемого клиенту в виде результата HTTP-запроса.

Существует несколько «результатов действия»:

Тип

Вспомогательный метод контроллера

Описание

РезультатДействияСодержимое

Содержимое()

Возвращает строковое тело HTTP ответа: текст, json, xml и т.п.

РезультатДействияФайл

Файл()

Инициирует скачивание файла клиентом

РезультатДействияПеренаправление

Перенаправление()

Инициирует редирект со стороны клиента

РезультатДействияКодСостояния

КодСостояния()

Отправляет на клиент код состояния HTTP. Например, 404

РезультатДействияСтраница

Представление()

Вызывает генерацию «представления (view)» и отправку результата на клиент

В первой колонке таблицы указан тип, который реализует тот или иной результат действия. Все эти типы могут быть созданы через оператор Новый и возвращены из метода-действия.

Однако, в Контроллере существуют вспомогательные методы, упрощающие создание указанных объектов. Эти методы перечислены во второй колонке таблицы.

Разбор на примере

Рассмотрим построчно код метода Add контроллера agents. Напомню, что он вызывается по URL /agents/add с использованием шаблона {controller}/{action}/{id?}

В коде будут даны комментарии по ключевым моментам обработки данного HTTP-запроса.

Функция Add() Экспорт

    // Проверяем, что Add вызван с помощью отправки формы методом HTTP POST
    Если ЗапросHttp.Метод = "POST" Тогда
        
        // Получаем контекст формы из HTTP-запроса
        НовыйID  = ЗапросHttp.ДанныеФормы["Идентификатор"];
        // Получаем сохраненный на сервере список известных центральных серверов
        ТЗ = ЦентральныеСерверы.ПолучитьСписок();
        // Создадим будущую запись таблицы центральных серверов.
        Элемент = ТЗ.Добавить();
        
        // Проверяем, что в форму добавления не ввели повторный идентификатор, 
        // который уже есть в базе.
        Элементы = ТЗ.НайтиСтроки(Новый Структура("Идентификатор", НовыйID));
        Если Элементы.Количество() > 0 Тогда
            // Регистрируем ошибку в специальном объекте СостояниеМодели
            СостояниеМодели.ДобавитьОшибку("Идентификатор","Такой ID уже есть в списке агентов");
            // Метод СохранитьДанные (см. ниже в коде)
            // наполняет Элемент значениями из ДанныхФормы
            СохранитьДанные(Элемент);
            // Отправляем эти данные обратно на клиента.
            // Поскольку это ошибка, то клиент должен увидеть ту же самую форму
            // Которую он заполнил, но с сообщениями из СостояниеМодели.
            // Для создания объекта РезультатДействияСтраница пользуемся вспомогательным методом контроллера Представление()
            Возврат Представление("Item", Элемент);
        КонецЕсли;
        
        // Если ошибки не было
        // наполняем Элемент из ДанныхФормы (метод СохранитьДанные см. ниже в коде)
        СохранитьДанные(Элемент);
        // Записываем на диск измененную таблицу центральных серверов.
        ЦентральныеСерверы.Записать(ТЗ);
        // Формируем объект РезультатДействияПеренаправление с помощью вспомогательного метода контроллера Перенаправление()
        Возврат Перенаправление("/agents/index");
    КонецЕсли;
    
    // А если это не метод POST, значит нам ничего не отправлено, а пользователь только-только запросил страницу /agents/add и собирается ввести данные нового агента.
    // Возвращаем клиенту форму с полями для заполнения.
    Возврат Представление("Item");

КонецФункции

Процедура СохранитьДанные(Знач Элемент)
    
    ДанныеФормы = ЗапросHttp.ДанныеФормы;
    Элемент.Идентификатор = ДанныеФормы["Идентификатор"];
    Элемент.СетевоеИмя = ДанныеФормы["СетевоеИмя"];
    Элемент.Порт = ДанныеФормы["Порт"];
    Элемент.Описание = ДанныеФормы["Описание"];
    Элемент.Режим = "RAS";

КонецПроцедуры

Заключение

На данный момент нет в сети ресурса с полным описанием всех методов и классов, доступных в веб-движке для 1Script. Работа над таким ресурсом ведется и, надеюсь, в ближайшее время он появится хотя бы в виде синтакс-помощника.

В этой главе мы узнали, как стартует веб-приложение, как настраиваются маршруты URL, по какому принципу пишется код контроллера и его методов действия, что такое «результат действия».

В следующей главе мы займемся непосредственно созданием операций администрирования.

  • Подключим библиотеку irac от Артема Кузнецова для программной работы с утилитами администрирования RAC/RAS.
  • Добавим контроллер управления списком кластеров в агенте
  • Расширим схему маршрутизации URL
  • Создадим боковую панель с элементами кластера: информационными базами, администраторами, серверами и т.п.

Оставайтесь на связи, и да пребудет с вами Сила! :)

См. также

Комментарии
2. Алексей Лустин (lustin) 902 23.04.18 10:09 Сейчас в теме
Если кому-то интересно построить собственное корпоративное приложение на oscript.web, а не на php - можете обращаться в качестве "ранних адаптаторов". Фактически мы такое делаем и код "почти на 1С".
3. Игорь Steelvan (Steelvan) 31 23.04.18 15:12 Сейчас в теме
Как будете решать вопрос отладки ?
Что будет в качестве среды проектирования ?
Будет ли конструктор форм ?
4. Андрей Овсянкин (Evil Beaver) 4990 23.04.18 16:15 Сейчас в теме
(3) Отладка будет, штатная, средствами Oscript Debugger. Среда разработки - VSCode
Конструктор форм пока не предполагается, т.к. речь не только о формах, но и вообще о UI приложения. Когда появятся более серьезные наработки по этой части - будем публиковать.
5. Игорь Steelvan (Steelvan) 31 23.04.18 22:14 Сейчас в теме
Я правильно понял, что весь js код для обозревателя разработчик должен писать самостоятельно ?

Oscript предлагает только серверную часть ?
6. Алексей Лустин (lustin) 902 24.04.18 18:26 Сейчас в теме
(5) Нет - не правильно, просто пока не публикуется в виде статьи. пока только gif'ки



На вопрос когда отвечу - как только фоновые задания допилятся, так сразу и будем работать над статьёй про фроненд

P.S. Фоновые задания тут https://github.com/EvilBeaver/OneScript.Web/pull/13
12. Андрей Овсянкин (Evil Beaver) 4990 25.04.18 18:35 Сейчас в теме
(5) В целом да, это серверная часть. Клиентский фронтенд и кодинг интерфейса клиента находятся на стадии научно-исследовательской работы. Доказано - кодить на 1С на клиенте - можно. Есть несколько концепций, есть наработки.
В статье дана оговорка, что сейчас это в рамках секретно-подпольной лаборатории, но рано или поздно - выйдет в свет.
7. Игорь Steelvan (Steelvan) 31 25.04.18 10:20 Сейчас в теме
Синтаксис сильно отличается от 1С. Это почти как новый язык учить.

А как будут выглядеть конструкции, типа "Если Тогда" или "Цикл КонецЦикла" ?
В виде "if() {}" и "for(;;)" ?
9. Александр Кунташов (kuntashov) 361 25.04.18 13:53 Сейчас в теме
(7) Вы про что? Синтаксис 1Script полностью совместим с 1С, вы куда-то не туда посмотрели.
10. Игорь Steelvan (Steelvan) 31 25.04.18 14:22 Сейчас в теме
(9) Вы про 1Script который на сервере, или в обозревателе ?

Мы про обозреватель переписываемся :)
11. Александр Кунташов (kuntashov) 361 25.04.18 18:21 Сейчас в теме
(10) Нет пока 1Скрипта в обозревателе, даже не понятно, где вы его увидеть смогли.

На скриншоте Алексея? Посмотрите внимательнее на скриншот: там последней строчкой "СкомпилироватьСНастройками()", это означает, что методы, которые вы видите выше просто генерируют HTML, но происходит это на сервере.

Т.е. это просто библиотека серверная, которая генерирует HTML-код веб-компонент или просто html-код.

Теоретически, на клиенте 1Скрипт можно сделать после выхода blazor'а.
13. Андрей Овсянкин (Evil Beaver) 4990 25.04.18 18:37 Сейчас в теме
(11) или сделать blazor, или сделать babel но для 1С - вариантов набирается на десяток, пробуем на вкус и оцениваем.
16. Андрей Овсянкин (Evil Beaver) 4990 25.04.18 18:55 Сейчас в теме
(11) Да, происходит генерация на сервере, но не статики. Генерируется в том числе и "реактивный" UI, откликающийся на изменение свойств связанных компонентов. И все это на языке 1С. Но да, это целый получается фреймворк, который надо осваивать. В этом пока главная проблема - упростить до привычных конструкций, не превратив это в жесткий "Управляемый интерфейс".
17. Александр Кунташов (kuntashov) 361 25.04.18 22:23 Сейчас в теме
(16) Я ничего не писал про статику, я написал "HTML-код веб-компонент", но подразумевал "код веб-компонент", т.к. какая разница, что на самом деле генерировать, "HTML" по инерции добавил )
18. Андрей Овсянкин (Evil Beaver) 4990 25.04.18 23:02 Сейчас в теме
(17) я просто счел нужным уточнить немного :)
19. Алексей Лустин (lustin) 902 01.05.18 16:41 Сейчас в теме
(17) Ты полностью прав. Пока я реализую обвязку - то есть классы и модули и функции поведения. Также выделил - темы и стили. Движок в рельности строит ASG на языке clojure, после чего с помощью lein сервера копилирует в минифифированный js (React.js). и как ты верно заметил я с очень большим интересом подсматриваю сюда https://github.com/aspnet/Blazor/tree/dev/samples/MonoSanity
kuntashov; +1 Ответить
15. Андрей Овсянкин (Evil Beaver) 4990 25.04.18 18:53 Сейчас в теме
(7) В идеале - Если Тогда, но сейчас этого нет.
8. Игорь Steelvan (Steelvan) 31 25.04.18 13:04 Сейчас в теме
И пара вопросов в догонку:
*) С какими типами будет работать разработчик: "Массив", "Число", "ТаблицаЗначений" или "Array", "Number" и "НетТаблицыВjs" ?
*) Нужно будет везде использовать "=" и система сама поймет, или "==" и ""===" ломая все привычки написания кода 1Сника ?
14. Андрей Овсянкин (Evil Beaver) 4990 25.04.18 18:51 Сейчас в теме
(8) Вы про код внутри view или про серверную логику?

Вся серверная логика - на 1С. Все привычные типы, таблицы значений и прочее - есть. Даже регламентные задания есть.
Что касается кода View, то движок представлений в принципе - вещь заменяемая. Один вытащил, другой вставил. Сейчас предлагается родной для ASP движок Razor. Это HTML плюс короткие вставки на C#. Самое главное, что C# учить не надо. Достаточно выучить простейшие конструкции @if и @foreach, поскольку все, что делает View - это отображает на экране переданную из кода 1С "Модель". Моделью может выступать любой объект - Массив, Структура, ТаблицаЗначений. И в коде Razor к ним можно обращаться привычным образом, через точку получая свойства и вызывая методы 1С.

@foreach(var КлючИЗначение in @Model.СтруктураЧегоНибудь){
    <td>Ключ        = @КлючИЗначение.Ключ</td>
    <td>Значение = @КлючИЗначение.Значение</td>
}


Однако, Razor - достаточно низкоуровневая штука, т.е. лежит очень близко к чистому HTML. Гораздо важнее уметь верстать HTML, а синтаксис Razor где-то на десятом месте. И это тоже 1С-нику непривычно.

На рынке существуют фронтенд-фреймворки React, Vue, Angular и прочие. Как-правило, современный UI пишется на них. Но это еще более непривычные 1С-нику штуки.

Итого имеем:

* Бизнес-логика - вся на 1С и привычна 1С-нику. Массив, Число, ТаблицаЗначений
* Разметка страниц, клиентская логика - на данный момент нет. Зато есть разнообразие готовых не-1С-инструментов, можно взять любой и выучить.
* Встроенный шаблонизатор Razor прост сам по себе, но требует умения верстать хотя бы чуть-чуть (2-3 часа в гугле, semantic, material, bootstrap).
* Рано или поздно, появятся готовые решения, позволяющие строить UI в привычной 1С-нику манере
* Есть вероятность, что в результате получится "Управляемый интерфейс", разметка которого прибита гвоздями и поменять ее сложно.
* Компромисс между свободой верстки и простотой создания UI всегда будет существовать, независимо от технологии
kuntashov; +1 Ответить
Оставьте свое сообщение