Основы создания серверных элементов управления. События.


Оглавление (нажмите, чтобы открыть):

Лекция 4. Разработка серверной части клиент-серверного приложения

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

Прежде всего следует определить, как будут размещены данные на сервере и как будут обрабатываться запросы, приходящие со стороны клиента. Также необходимо продумать организацию серверного кэширования данных.

Необходимо определиться с протоколами обмена данными и форматами передачи данных.

API (application programming interface) – интерфейс прикладного программирования. Если выражаться более понятным языком, то это набор запросов к серверу, который последний понимает и может дать корректный ответ. API определяет функциональность серверной логики, при этом API позволяет абстрагироваться от того, как именно эта функциональность реализована. Другими словами, API – это необходимая часть общей клиент-серверной инфраструктуры.

Сравнить JSON и XML. Привести пример протоколов в зависимости от типа приложения.

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

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

Сутью многопоточности является квазимногозадачность на уровне одного исполняемого процесса, то есть все потоки выполняются в адресном пространстве процесса. Кроме этого, все потоки процесса имеют не только общее адресное пространство, но и общие дескрипторы файлов. Выполняющийся процесс имеет как минимум один (главный) поток.

Многопоточность (как доктрину программирования) не следует путать ни с многозадачностью, ни с многопроцессорностью, несмотря на то, что операционные системы, реализующие многозадачность, как правило, реализуют и многопоточность.

К достоинствам многопоточности в программировании можно отнести следующее:

Упрощение программы в некоторых случаях за счёт использования общего адресного пространства.

Меньшие относительно процесса временные затраты на создание потока.

Повышение производительности процесса за счёт распараллеливания процессорных вычислений и операций ввода-вывода.

Поток (threаd) – это управляемая единица исполняемого кода. В многозадачной среде, основанной на потоках, у всех работающих процессов обязательно имеется основной поток, но их может быть и больше. Это означает, что в одной программе могут выполняться несколько задач асинхронно. К примеру, редактирование текста в текстовом редакторе во время печати, т.к эти две задачи выполняются в различных потоках.

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

– Временная многопоточность (один поток)

– Одновременная многопоточность (несколько потоков одновременно)

Многопоточность, как широко распространённая модель программирования и исполнения кода, позволяет нескольким потокам выполняться в рамках одного процесса. Эти потоки выполнения совместно используют ресурсы процесса, но могут работать и самостоятельно. Многопоточная модель программирования предоставляет разработчикам удобную абстракцию параллельного выполнения. Однако, пожалуй, наиболее интересное применение технологии имеется в том случае, когда она применяется к одному процессу, что позволяет его параллельное выполнение на многопроцессорной системе.

Это преимущество многопоточной программы позволяет ей работать быстрее на компьютерных системах, которые имеют несколько процессоров, процессор с несколькими ядрами или на кластере машин — из-за того, что потоки выполнения программ естественным образом поддаются действительно параллельному выполнению процессов. В этом случае программисту нужно быть очень осторожным, чтобы избежать состояния гонки, и другого неинтуитивного поведения. Для того, чтобы правильно манипулировать данными, потоки выполнения должны часто проходить через процедуру рандеву, чтобы обрабатывать данные в правильном порядке. Потокам выполнения могут также потребоваться мьютексы (которые часто реализуются с использованием семафоров), чтобы предотвратить одновременное изменение общих данных или их чтение во время процесса изменения. Неосторожное использование таких примитивов может привести к тупиковой ситуации.

Другим использованием многопоточности, применяемым даже для однопроцессорных систем, является возможность для приложения реагирования на ввод данных. В однопоточных программах, если основной поток выполнения заблокирован выполнением длительной задачи, всё приложение может оказаться в замороженном состоянии. Перемещая такие длительные задачи в рабочий поток, который выполняется параллельно с основным потоком, становится возможным для приложений продолжать реагировать на действия пользователя во время выполнения задач в фоновом режиме. С другой стороны, в большинстве случаев многопоточность – не единственный способ сохранить чувствительность программы. То же самое может быть достигнуто через асинхронный ввод-вывод или сигналы в UNIX.

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

Всего различают два типа потоков:

Потоки переднего плана (foreground threads) или приоритетный. По умолчанию каждый поток, создаваемый через метод Thread.Start(), автоматически становится потоком переднего плана. Данный тип потоков обеспечивают предохранение текущего приложения от завершения. Среда CLR не остановит приложение до тех пор, пока не будут завершены все приоритетные потоки.

Фоновые потоки (background threads). Данный вид потоков называется также потоками-демонами, воспринимаются средой CLR как расширяемые пути выполнения, которые в любой момент времени могут игнорироваться. Таким образом, если все потоки переднего плана прекращаются, то все фоновые потоки автоматически уничтожаются при выгрузке домена приложения. Для создания фоновых потоков необходимо присвоить свойству IsBackground значение true.

Рассказать про состояния потоков: запущенный, приостановленный, запущенный, но ожидающий чего-то.

Проблема синхронизации потоков и общие ресурсы.

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

Мьютекс – это объект синхронизации, который устанавливается в особое сигнальное состояние, когда не занят каким-либо потоком. Только один поток владеет этим объектом в любой момент времени, отсюда и название таких объектов (от английского mutually exclusive access — взаимно исключающий доступ) — одновременный доступ к общему ресурсу исключается. После всех необходимых действий мьютекс освобождается, предоставляя другим потокам доступ к общему ресурсу. Объект может поддерживать рекурсивный захват второй раз тем же потоком, увеличивая счетчик, не блокируя поток, и требуя потом многократного освобождения. Такова, например, критическая секция в Win32. Тем не менее, есть и такие реализации, которые не поддерживают такое и приводят к взаимной блокировке потока при попытке рекурсивного захвата. Это FAST_MUTEX в ядре Windows.

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

События. Объект, хранящий в себе 1 бит информации «просигнализирован или нет», над которым определены операции «просигнализировать», «сбросить в непросигнализированное состояние» и «ожидать». Ожидание на просигнализированном событии есть отсутствие операции с немедленным продолжением исполнения потока. Ожидание на непросигнализированном событии приводит к приостановке исполнения потока до тех пор, пока другой поток (или же вторая фаза обработчика прерывания в ядре ОС) не просигнализирует событие. Возможно ожидание нескольких событий в режимах «любого» или «всех». Возможно также создание события, автоматически сбрасываемого в непросигнализированное состояние после пробуждения первого же – и единственного – ожидающего потока (такой объект используется как основа для реализации объекта «критическая секция»). Активно используются в MS Windows, как в режиме пользователя, так и в режиме ядра. Аналогичный объект имеется и в ядре Linux под названием kwait_queue.

Критические секции обеспечивают синхронизацию подобно мьютексам, за исключением того, что объекты, представляющие критические секции, доступны в пределах одного процесса. События, мьютексы и семафоры также можно использовать в однопроцессном приложении, однако реализации критических секций в некоторых ОС (например, Windows NT) обеспечивают более быстрый и более эффективный механизм взаимно-исключающей синхронизации – операции «получить» и «освободить» на критической секции оптимизированы для случая единственного потока (отсутствия конкуренции) с целью избежать любых ведущих в ядро ОС системных вызовов. Подобно мьютексам объект, представляющий критическую секцию, может использоваться только одним потоком в данный момент времени, что делает их крайне полезными при разграничении доступа к общим ресурсам.

Условные переменные (condvars). Сходны с событиями, но не являются объектами, занимающими память – используется только адрес переменной, понятие «содержимое переменной» не существует, в качестве условной переменной может использоваться адрес произвольного объекта. В отличие от событий, установка условной переменной в просигнализированное состояние не влечет за собой никаких последствий в случае, если на данный момент нет потоков, ожидающих на переменной. Установка события в аналогичном случае влечет за собой запоминание состояния «просигнализировано» внутри самого события, после чего следующие потоки, желающие ожидать события, продолжают исполнение немедленно без остановки. Для полноценного использования такого объекта необходима также операция «освободить mutex и ожидать условную переменную атомарно». Активно используются в UNIX-подобных ОС. Дискуссии о преимуществах и недостатках событий и условных переменных являются заметной частью дискуссий о преимуществах и недостатках Windows и UNIX.

Порт завершения ввода-вывода (IO completion port, IOCP). Реализованный в ядре ОС и доступный через системные вызовы объект «очередь» с операциями «поместить структуру в хвост очереди» и «взять следующую структуру с головы очереди» — последний вызов приостанавливает исполнение потока в случае, если очередь пуста, и до тех пор, пока другой поток не осуществит вызов «поместить». Самой важной особенностью IOCP является то, что структуры в него могут помещаться не только явным системным вызовом из режима пользователя, но и неявно внутри ядра ОС как результат завершения асинхронной операции ввода-вывода на одном из дескрипторов файлов. Для достижения такого эффекта необходимо использовать системный вызов «связать дескриптор файла с IOCP». В этом случае помещенная в очередь структура содержит в себе код ошибки операции ввода-вывода, а также, для случая успеха этой операции — число реально введенных или выведенных байт. Реализация порта завершения также ограничивает число потоков, исполняющихся на одном процессоре/ядре после получения структуры из очереди. Объект специфичен для MS Windows, и позволяет обработку входящих запросов соединения и порций данных в серверном программном обеспечении в архитектуре, где число потоков может быть меньше числа клиентов (нет требования создавать отдельный поток с расходами ресурсов на него для каждого нового клиента).

Базовый принцип программирования управляемой формы в 1С

Цель статьи – показать применение шаблонов Remote Facade и Data Transfer Object к структуризации кода, управляемой формы в среде 1С 8.2.

Введение

Начнем с небольшого описания понятия «управляемая форма» и связанных концепций платформы 1С. Знатоки платформы могут пропустить этот раздел.

В 2008 году стала доступна новая версия платформы 1С: Предприятие 8.2 (далее Управляемое приложение), которая полностью меняет весь слой работы с интерфейсом. Сюда относится и командный интерфейс, и формы, и оконная система. При этом не только меняется модель разработки пользовательского интерфейса в конфигурации, но и предлагается новая архитектура разделения функциональности между клиентским приложением и сервером.
Управляемое приложение поддерживает следующие типы клиентов:

  • Толстый клиент (обычный и управляемый режим запуска)
  • Тонкий клиент
  • Веб-клиент

В управляемом приложении используются формы, построенные на новой технологии. Они называются Управляемые формы. Для облегчения перехода прежние формы (т.н. Обычные формы) также поддерживаются, но их функциональность не развивается и они доступны только в режиме запуска толстого клиента.
Основные отличия управляемых форм для разработчика:

  • Декларативное, а не «по пикселям» описание структуры. Конкретное размещение элементов выполняется системой автоматически при отображении формы.
  • Вся функциональность формы описывается в виде реквизитов и команд. Реквизиты – это данные, с которыми работает форма, а команды – выполняемые действия.
  • Форма выполняется и на сервере и на клиенте.
  • В контексте клиента, недоступны практически все прикладные типы, и соответственно невозможно изменить данные в информационной базе.
  • Для каждого метода или переменной формы обязательно должна быть указана директива компиляции, определяющая, место выполнения (клиент или сервер) и доступ к контексту формы.

Перечислим директивы компиляции методов формы:

  • &НаКлиенте
  • &НаСервере
  • &НаСервереБезКонтекста
  • &НаКлиентеНаСервереБезКонтекста

Проиллюстрируем перечисленное. На скриншоте пример управляемой формы и ее модуля в режиме разработки. Найдите декларативное описание, реквизиты, директивы компиляции и т.д.

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

Обозначим проблему

Прошло уже несколько лет как новая версия платформы 1С активно используется и выпущено множество решений (конфигураций) как фирмой 1С, так и ее многочисленными партнерами.
Сложилось ли за это время у разработчиков единое понимание принципов клиент-серверного взаимодействия при создании форм, и изменился ли подход к реализации программных модулей в новых архитектурных реалиях?

Рассмотрим структуру кода (модуль формы) в нескольких формах одной типовой конфигурации и попробуем найти закономерности.
Под структурой будем понимать секции кода (чаще всего это блоки комментариев) выделенные разработчиком для группировки методов и директивы компиляции этих методов.
Пример 1:

По сути, структура кода отсутствует, или мягче говоря, она аналогична тому, что было в формах 8.1:

  • Неинформативные слова «Общие, Служебные, Вспомогательные».
  • Робкие попытки разделить клиентские и серверные методы.
  • Часто методы группируются по интерфейсным элементам «Работа с табличной частью Товары, Контактной информацией».
  • Произвольное расположение методов и групп кода. Например, Обработчики событий могут быть в одной форме вверху, в другой внизу, в третьей вообще не выделены и т.д.
  • И не будем забывать, что это все в рамках одной конфигурации.
  • Да бывают конфигурации, в которых слова «Общие, Служебные, Вспомогательные» всегда находятся на одних и тех же местах но…

Зачем нужна структура кода?
Почему существующий стандарт разработки от фирмы 1С не помогает?

Посмотрим опубликованные на дисках ИТС и в различных «Пособиях разработчика…» принципы, рекомендуемые при написании управляемой формы.

  • Минимизируйте число серверных вызовов.
  • Максимум вычислений на сервере.
  • Неконтекстные вызовы сервера быстрее контекстных.
  • Программируйте с учетом клиент-серверного взаимодействия.
  • и т.п.

Это лозунги, абсолютно верные, но как их реализовать? Как минимизировать число вызовов, что значит программировать в клиент-серверном режиме?

Шаблоны проектирования или мудрость поколений

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

  • Remote Facade (далее Интерфейс удаленного доступа)
  • Data Transfer Object (далее Объект переноса данных)

Слово Мартину Фаулеру, его описание данных принципов:

  • каждый объект, потенциально предназначенный для удаленного доступа, должен иметь интерфейс с низкой степенью детализации, что позволит максимально уменьшить количество вызовов, необходимых для выполнения определенной процедуры. … Вместо того, чтобы запрашивать счёт и все его пункты отдельно, надо считать и обновить все пункты счёта за одно обращение. Это влияет на всю структуру объекта.…Запомните: интерфейс удаленного доступа не содержит логики домена.
  • …если бы я был заботливой мамой, то обязательно сказал бы своему ребенку: «Никогда не пиши объекты переноса данных!» В большинстве случаев объекты переноса данных представляют собой не более чем раздутый набор полей … Ценность этого омерзительного монстра состоит исключительно в возможности передавать по сети несколько элементов информации за один вызов — прием, который имеет большое значение для распределенных систем.
Примеры шаблонов в платформе 1С

Прикладной программный интерфейс доступный разработчику при разработке управляемой формы, содержит много примеров данных принципов.
Например метод ОткрытьФорму(), типичный «огрубленный» интерфейс.

Сравните с принятым в v8.1 стилем.

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

  • ДанныеФормыСтруктура
  • ДанныеФормыКоллекция
  • ДанныеФормыСтруктураСКоллекцией
  • ДанныеФормыДерево

Преобразование системных объектов переноса данных в прикладные типы и обратно выполняется методами:

  • ЗначениеВДанныеФормы()
  • ДанныеФормыВЗначение()
  • КопироватьДанныеФормы()
  • ЗначениеВРеквизитФормы()
  • РеквизитФормыВЗначение()

Часто явное преобразование используется при адаптации существующего решения. Методы могут ожидать (использовать особенности) входные параметры, например ТаблицаЗначений, а не ДанныеФормыКоллекция, или метод был определен в контексте прикладного объекта и стал недоступен для прямого вызова из формы.
Пример 1С v8.1:

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

  • Примитивные типы (строка, число, булево)
  • Структура
  • Соответствие
  • Массив
  • Ссылки на прикладные объекты (уникальный идентификатор и текстовое представление)

Пример: метод принимает список заказов для изменения статуса и возвращает клиенту описание ошибок.

Структурируем код

Главные цели, которые должен отражать модуль управляемой формы и подходы к решению.

  • Четкое разделение клиентского и серверного кода. Не будем забывать, в момент выполнения это два взаимодействующих процесса, в каждом из которых существенно отличается доступный функционал.
  • Четкое выделение интерфейса удаленного доступа, какие методы сервера можно вызывать с клиента, а какие нельзя? Названия методов удаленного интерфейса начинаются с префикса «Сервер». Это позволяет, читая код сразу видеть переход управления на сервер, и упрощает использование контекстной подсказки. Отметим, что официальная рекомендация (ИТС) предлагает именовать методы с постфиксами, например, так ИзменитьСтатусЗаказовНаСервере(). Однако повторим не все серверные методы можно вызывать с клиента, и поэтому более важна логическая доступность, а не место компиляции. Поэтому префиксом «Сервер» отмечаем только методы доступные для клиента, метод-пример назовем СерверИзменитьСтатусЗаказов().
  • Удобочитаемость. Дело вкуса, принимаем порядок, когда модуль начинается с процедур создания формы на сервере и методов удаленного доступа.
  • Сопровождаемость. Должно быть однозначно определено место для добавления нового кода. Важный момент, автоматически создаваемые конфигуратором заготовки методов добавляются в конец модуля. Т.к чаще всего автоматически создаются обработчики событий элементов формы, то соответствующий блок расположен последним, чтобы не перетаскивать каждый обработчик в другое место модуля.

Ниже приведена базовая структура модуля, реализующая перечисленные цели.

  • Графический вариант – наглядно показывает основной поток выполнения.
  • Текстовый вариант — это пример оформления шаблона для быстрой вставки структуры в новый модуль формы.

Грамотная клиент-серверная архитектура: как правильно проектировать и разрабатывать web API

Рассказывает Владимир, веб-разработчик Noveo

Большинству разработчиков сайтов, веб-сервисов и мобильных приложений рано или поздно приходится иметь дело с клиент-серверной архитектурой, а именно разрабатывать web API или интегрироваться с ним. Чтобы не изобретать каждый раз что-то новое, важно выработать относительно универсальный подход к проектированию web API, основываясь на опыте разработки подобных систем. Предлагаем вашему вниманию объединенный цикл статей, посвящённых этому вопросу.


Приближение первое: Действующие лица

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

Чтиво получилось больше философское, нежели техническое, но и для любителей технической части здесь будет над чем поразмыслить. Сомневаюсь, что скажу в этой статье что-то принципиально новое, то, о чем вы никогда не слышали, не читали и о чем не думали сами. Просто попытаюсь уложить все в единую систему, в первую очередь в своей собственной голове, а это уже дорогого стоит. Тем не менее, буду рад, если мои измышления будут вам полезны в вашей практике. Итак, поехали.

Клиент и сервер

Сервером в данном случае мы считаем абстрактную машину в сети, способную получить HTTP-запрос, обработать его и вернуть корректный ответ. В контексте данной статьи совершенно не важны его физическая суть и внутренняя архитектура, будь то студенческий ноутбук или огромный кластер из промышленных серверов, разбросанных по всему миру. Нам в той же мере совершенно неважно, что у него под капотом, кто встречает запрос у дверей, Apache или Nginx, какой неведомый зверь, PHP, Python или Ruby выполняет его обработку и формирует ответ, какое хранилище данных используется: Postgresql, MySQL или MongoDB. Главное, чтобы сервер отвечал главному правилу — услышать, понять и простить ответить.

Клиентом тоже может быть все, что угодно, что способно сформировать и отправить HTTP-запрос. До определенного момента в этой статье нам также не особо будут интересны цели, которые ставит перед собой клиент, отправляя этот запрос, как и то, что он будет делать с ответом. Клиентом может быть JavaScript-сценарий, работающий в браузере, мобильное приложение, злой (или не очень) демон, запущенный на сервере, или слишком поумневший холодильник (уже есть и такие).

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

Философия REST

REST (Representational state transfer) изначально был задуман как простой и однозначный интерфейс для управления данными, предполагавший всего несколько базовых операций с непосредственным сетевым хранилищем (сервером): извлечение данных (GET), сохранение (POST), изменение (PUT/PATCH) и удаление (DELETE). Разумеется, этот перечень всегда сопровождался такими опциями, как обработка ошибок в запросе (корректно ли составлен запрос), разграничение доступа к данным (вдруг этого вам знать не следует) и валидация входящих данных (вдруг вы написали ерунду), в общем, всеми возможными проверками, которые сервер выполняет перед тем, как выполнить желание клиента.

Помимо этого REST имеет ряд архитектурных принципов, перечень которых можно найти в любой другой статье о REST. Пробежимся по ним кратко, чтобы они были под рукой, и не пришлось никуда уходить:

Независимость сервера от клиента — серверы и клиенты могут быть мгновенно заменены другими независимо друг от друга, так как интерфейс между ними не меняется. Сервер не хранит состояний клиента.
Уникальность адресов ресурсов — каждая единица данных (любой степени вложенности) имеет свой собственный уникальный URL, который, по сути, целиком является однозначным идентификатором ресурса.

Пример: GET /api/v1/users/25/name

Независимость формата хранения данных от формата их передачи — сервер может поддерживать несколько различных форматов для передачи одних и тех же данных (JSON, XML и т.д.), но хранит данные в своем внутреннем формате, независимо от поддерживаемых.

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

Чего нам не хватает

Классический REST подразумевает работу клиента с сервером как с плоским хранилищем данных, при этом ничего не говорится о связанности и взаимозависимости данных между собой. Все это по умолчанию целиком ложится на плечи клиентского приложения. Однако современные предметные области, для которых разрабатываются системы управления данными, будь то социальные сервисы или системы интернет-маркетинга, подразумевают сложную взаимосвязь между сущностями, хранящимися в базе данных. Поддержка этих связей, т.е. целостности данных, находится в зоне ответственности серверной стороны, в то время, как клиент является только интерфейсом для доступа к этим данным. Так чего же нам не хватает в REST?

Вызовы функций

Чтобы не менять данные и связи между ними вручную, мы просто вызываем у ресурса функцию и «скармливаем» ей в качестве аргумента необходимые данные. Эта операция не подходит под стандарты REST, для нее не существует особого глагола, что заставляет нас, разработчиков, выкручиваться кто во что горазд.

Мастер Йода рекомендует:  Макет сайта как средство выражения индивидуальности

Самый простой пример – авторизация пользователя. Мы вызываем функцию login, передаем ей в качестве аргумента объект, содержащий учетные данные, и в ответ получаем ключ доступа. Что творится с данными на серверной стороне – нас не волнует.

Еще вариант – создание и разрыв связей между данными. Например, добавление пользователя в группу. Вызываем у сущности группа функцию addUser, в качестве параметра передаем объект пользователь, получаем результат.

А еще бывают операции, которые вообще не связаны напрямую с сохранением данных как таковых, например, рассылка уведомлений, подтверждение или отклонение каких-либо операций (завершение отчетного периода etc).

В одной из следующих статей я постараюсь классифицировать эти операции и предложить варианты возможных запросов и ответов, основываясь на том, с какими из них мне приходилось сталкиваться на практике.

Множественные операции

Часто бывает так, и разработчики клиентов поймут, о чем я, что клиентскому приложению удобнее создавать/изменять/удалять/ сразу несколько однородных объектов одним запросом, и по каждому объекту возможен свой вердикт серверной стороны. Тут есть как минимум несколько вариантов: либо все изменения выполнены, либо они выполнены частично (для части объектов), либо произошла ошибка. Ну и стратегий тоже несколько: применять изменения только в случае успеха для всех, либо применять частично, либо откатываться в случае любой ошибки, а это уже тянет на полноценный механизм транзакций.

Для web API, стремящегося к идеалу, тоже хотелось бы как-то привести подобные операции в систему. Постараюсь сделать это в одном из продолжений.

Статистические запросы, агрегаторы, форматирование данных

Частенько бывает так, что на основе хранимых на сервере данных нам нужно получить статистическую выжимку или данные, отформатированные особым образом: например, для построения графика на стороне клиента. По сути это данные, генерируемые по требованию, в той или иной мере на лету, и доступные только для чтения, так что имеет смысл вынести их в отдельную категорию. Одной из отличительных особенностей статистических данных, на мой взгляд, является то, что они не имеют уникального ID.

Уверен, что это далеко не все, с чем можно столкнуться при разработке реальных приложений, и буду рад вашим дополнениям и коррективам.

Разновидности данных

Объекты

Ключевым типом данных в общении между клиентом и сервером выступает объект. По сути, объект – это перечень свойств и соответствующих им значений. Мы можем отправить объект на сервер в запросе и получить в результат запроса в виде объекта. При этом объект не обязательно будет реальной сущностью, хранящейся в базе данных, по крайней мере, в том виде, в котором он отправлен или получен. Например, учетные данные для авторизации передаются в виде объекта, но не являются самостоятельной сущностью. Даже хранимые в БД объекты склонны обрастать дополнительными свойствами внутрисистемного характера, например, датами создания и редактирования, различными системными метками и флагами. Свойства объектов могут быть как собственными скалярными значениями, так и содержать связанные объекты и коллекции объектов, которые не являются частью объекта. Часть свойств объектов может быть редактируемой, часть системной, доступной только для чтения, а часть может носить статистический характер и вычисляться на лету (например, количество лайков). Некоторые свойства объекта могут быть скрыты, в зависимости от прав пользователя.

Коллекции объектов

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

Скалярные значения

В чистом виде скалярные значения как отдельная сущность на моей памяти встречались крайне редко. Обычно они фигурировали как свойства объектов или коллекций, и в этом качестве они могут быть доступны как для чтения, так и для записи. Например, имя пользователя может быть получено и изменено в индивидуальном порядке GET /users/1/name . На практике эта возможность пригождается редко, но в случае необходимости хотелось бы, чтобы она была под рукой. Особенно это касается свойств коллекции, например числа записей (с фильтрацией или без нее): GET /news/count .

В одной из следующих статей я постараюсь классифицировать эти операции и предложить варианты возможных запросов и ответов, основываясь на том, с какими из них мне приходилось сталкиваться на практике.

Приближение второе: Правильный путь

В этом приближении я хотел бы отдельно поговорить о подходах к построению уникальных путей к ресурсам и методам вашего web API и о тех архитектурных особенностях приложения, которые влияют на внешний вид этого пути и его компоненты.

О чем стоит подумать, стоя на берегу

Версионность

Рано или поздно любая действующая система начинает эволюционировать: развиваться, усложняться, масштабироваться, усовремениваться. Для разработчиков REST API это чревато в первую очередь тем, что необходимо запускать новые версии API при работающих старых. Здесь я говорю больше не об архитектурных изменениях под капотом вашей системы, а о том, что изменяется сам формат данных и набор операций с ними. В любом случае версионность нужно предусмотреть как в изначальной организации исходного кода, так и в принципе построения URL. Что касается URL, здесь существует два наиболее популярных способа указания версии API, которой адресован запрос. Префиксация пути example-api.com/v1/ и разведение версий на уровне субдомена v1.example-api.com . Использовать можно любой из них, в зависимости от потребности и необходимости.

Автономность компонентов

Web API сложных систем, поддерживающих несколько пользовательских ролей, зачастую требует разделения на части, каждая из которых обслуживает свой спектр задач. По сути, каждая часть может быть самостоятельным приложением, работать на разных физических машинах и платформах. В контексте описания API нам совершенно не важно, как сервер обрабатывает запрос и какие силы и технологии в этом замешаны. Для клиента API – система инкапсулированная. Тем не менее разные части системы могут обладать совершенно разной функциональностью, например, административная и пользовательская часть. И методология работы с одними и теми же, казалось бы, ресурсами может существенно отличаться. Поэтому такие части необходимо разделять на уровне домена admin.v1.example-api.com или префикса пути example-api.com/v1/admin/ . Это требование не является обязательным, и многое зависит от сложности системы и её назначения.

Формат обмена данными

Самым удобным и функциональным, на мой взгляд, форматом обмена данными является JSON, но никто не запрещает использовать XML, YAML или любой другой формат, позволяющий хранить сериализованные объекты без потери типа данных. При желании можно сделать в API поддержку нескольких форматов ввода/вывода. Достаточно задействовать HTTP заголовок запроса для указания желаемого формата ответа Accept и Content-Type для указания формата переданных в запросе данных. Другим популярным способом является добавление расширения к URL ресурса, например, GET /users.xml , но такой способ кажется менее гибким и красивым, хотя бы потому, что утяжеляет URL и верен скорее для GET-запросов, нежели для всех возможных операций.

Локализация и многоязычность

На практике многоязычность API чаще всего сводится к переводу сервисных сообщений и сообщений об ошибках на требуемый язык для прямого отображения конечному пользователю. Многоязычный контент тоже имеет место быть, но сохранение и выдача контента на разных языках, на мой взгляд, должна разграничиваться более явно, например, если у вас одна и та же статья существует на разных языках, то по факту это две разных сущности, сгруппированные по признаку единства содержания. Для идентификации ожидаемого языка можно использовать разные способы. Самым простым можно считать стандартный HTTP-заголовок Accept-Language . Я встречал и другие способы, такие, как добавление GET-параметра language=»en» , использование префикса пути example-api.com/en/ или даже на уровне доменного имени en.example-api.com . Мне кажется, что выбор способа указания локали зависит от конкретного приложения и задач, стоящих перед ним.

Внутренняя маршрутизация

Итак, мы добрались до корневого узла нашего API (или одного из его компонентов). Все дальнейшие маршруты будут проходить уже непосредственно внутри вашего серверного приложения, в соответствии с поддерживаемым им набором ресурсов.

Пути к коллекциям

Для указания пути к коллекции мы просто используем название соответствующей сущности, например, если это список пользователей, то путь будет таким /users . К коллекции как таковой применимы два метода: GET (получение лимитированного списка сущностей) и POST (создание нового элемента). В запросах на получение списков мы можем использовать множество дополнительных GET параметров, применяемых для постраничного вывода, сортировки, фильтрации, поиска etc, но они должны быть опциональными, т.е. эти параметры не должны передаваться как часть пути!

Элементы коллекции

Для обращения к конкретному элементу коллекции мы используем в маршруте его уникальный идентификатор /users/25 . Это и есть уникальный путь к нему. Для работы с объектом применимы методы GET (получение объекта), PUT/PATCH (изменение) и DELETE (удаление).

Уникальные объекты

Во множестве сервисов существуют уникальные для текущего пользователя объекты, например профиль текущего пользователя /profile , или персональные настройки /settings . Разумеется, с одной стороны, это элементы одной из коллекций, но они являются отправной точкой в использовании нашего Web API клиентским приложением, и к тому же позволяют намного более широкий спектр операций над данными. При этом коллекция, хранящая пользовательские настройки может быть вообще недоступна из соображений безопасности и конфиденциальности данных.

Свойства объектов и коллекций

Для того, чтобы добраться до любого из свойств объекта напрямую, достаточно добавить к пути до объекта имя свойства, например получить имя пользователя /users/25/name . К свойству применимы методы GET (получение значения) и PUT/PATCH (изменение значения). Метод DELETE не применим, т.к. свойство является структурной частью объекта, как формализованной единицы данных.

В предыдущей части мы говорили о том, что у коллекций, как и у объектов, могут быть собственные свойства. На моей памяти мне пригодилось только свойство count, но ваше приложение может быть более сложным и специфичным. Пути к свойствам коллекций строятся по тому же принципу, что и к свойствам их элементов: /users/count . Для свойств коллекций применим только метод GET (получение свойства), т.к. коллекция – это только интерфейс для доступа к списку.

Коллекции связанных объектов

Одной из разновидностей свойств объектов могут быть связанные объекты или коллекции связанных объектов. Такие сущности, как правило, не являются собственным свойством объекта, а лишь отсылками к его связям с другими сущностями. Например, перечень ролей, которые были присвоены пользователю /users/25/roles . По поводу работы с вложенными объектами и коллекциями мы подробно поговорим в одной из следующих частей, а на данном этапе нам достаточно того, что мы имеем возможность обращаться к ним напрямую, как к любому другому свойству объекта.

Функции объектов и коллекций

Для построения пути к интерфейсу вызова функции у коллекции или объекта мы используем тот же самый подход, что и для обращения к свойству. Например, для объекта /users/25/sendPasswordReminder или коллекции /users/disableUnconfirmed . Для вызовов функций мы в любом случае используем метод POST. Почему? Напомню, что в классическом REST не существует специального глагола для вызова функций, а потому нам придется использовать один из существующих. На мой взгляд, для этого больше всего подходит метод POST т.к. он позволяет передавать на сервер необходимые аргументы, не является идемпотентным (возвращающим один и тот же результат при многократном обращении) и наиболее абстрактен по семантике.

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

Приближение третье: Запросы и ответы

В предыдущих приближениях я рассказал о том, как пришла идея собрать и обобщить имеющийся опыт разработки web API. В первой части я постарался описать, с какими видами ресурсов и операций над ними мы имеем дело при проектировании web API. Во второй части были затронуты вопросы построения уникальных URL для обращения к этим ресурсам. А в этом приближении я попробую описать возможные варианты запросов и ответов.

Универсальный ответ

Мы уже проговаривали, что конкретный формат общения сервера с клиентом может быть любым на усмотрение разработчика. Для меня наиболее удобным и наглядным кажется формат JSON, хотя в реальном приложении может быть реализована поддержка нескольких форматов. Сейчас же сосредоточимся на структуре и необходимых атрибутах объекта ответа. Да, все данные, возвращаемые сервером, мы будем оборачивать в специальный контейнер — универсальный объект ответа, который будет содержать всю необходимую сервисную информацию для его дальнейшей обработки. Итак, что это за информация:

Success — маркер успешности выполнения запроса

Для того, чтобы при получении ответа от сервера сразу понять, увенчался ли запрос успехом, и передать его соответствующему обработчику, достаточно использовать маркер успешности «success». Самый простой ответ сервера, не содержащий никаких данных, будет выглядеть так:

Error — сведения об ошибке

В случае, если выполнение запроса завершилось неудачей — о причинах и разновидностях отрицательных ответов сервера поговорим чуть позже, — к ответу добавляется атрибут «error», содержащий в себе HTTP-код статуса и текст сообщения об ошибке. Прошу не путать с сообщениями об ошибках валидации данных для конкретных полей. Правильнее всего, на мой взгляд, возвращать код статуса и в заголовке ответа, но я встречал и другой подход — в заголовке всегда возвращать статус 200 (успех), а детали и возможные данные об ошибках передавать в теле ответа.


Data — данные, возвращаемые сервером

Большинство ответов сервера призваны возвращать данные. В зависимости от типа запроса и его успеха ожидаемый набор данных будет разным, тем не менее атрибут«data» будет присутствовать в подавляющем большинстве ответов.

Пример возвращаемых данных в случае успеха. В данном случае ответ содержит запрашиваемый объект user.

Пример возвращаемых данных в случае ошибки. В данном случае содержит имена полей и сообщения об ошибках валидации.

Pagination — сведения, необходимые для организации постраничной навигации

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

Минимальный набор значений для пагинации состоит из:

  • общего числа записей;
  • числа страниц;
  • номера текущей страницы;
  • числа записей на странице;
  • максимального числа записей на странице, поддерживаемого серверной стороной.

Некоторые разработчики web API также включают в пагинацию набор готовых ссылок на соседние страницы, а также первую, последнюю и текущую.

Работа над ошибками

Как уже упоминалось выше, не все запросы к web API завершаются успехом, но это тоже часть игры. Система информирования об ошибках является мощным инструментом, облегчающим работу клиента и направляющим клиентское приложение по правильному пути. Слово «ошибка» в этом контексте не совсем уместно. Здесь больше подойдёт слово исключение, так как на самом деле запрос успешно получен, проанализирован, и на него возвращается адекватный ответ, объясняющий, почему запрос не может быть выполнен.

Каковы же потенциальные причины получаемых исключений?

500 Internal server error — всё сломалось, но мы скоро починим

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

400 Bad request — а теперь у вас всё сломалось

Ответ прямо противоположный предыдущему. Возвращается в тех случаях, когда клиентское приложение отправляет запрос, который в принципе не может быть корректно обработан, не содержит обязательных параметров или имеет синтаксические ошибки. Обычно это лечится повторным прочтением документации к web API.

401 Unauthorized — незнакомец, назови себя

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

403 Forbidden — вам сюда нельзя

Запрашиваемый ресурс существует, но у пользователя недостаточно прав на его просмотр или модификацию.

404 Not found — по этому адресу никто не живёт

Такой ответ возвращается, как правило, в трёх случаях: путь к ресурсу неверен (ошибочен), запрашиваемый ресурс был удалён и перестал существовать, права текущего пользователя не позволяют ему знать о существовании запрашиваемого ресурса. Например, пока просматривали список товаров, один из них внезапно вышел из моды и был удалён.

405 Method not allowed — нельзя такое делать

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

422 Unprocessable entity — исправьте и пришлите снова

Одно из самых полезных исключений. Возвращается каждый раз, когда в данных запроса существуют логические ошибки. Под данными запроса мы подразумеваем либо набор параметров и соответствующих им значений, переданных методом GET, либо поля объекта, передаваемого в теле запроса методами POST, PUT и DELETE. Если данные не прошли валидацию, сервер в секции «data» возвращает отчет о том, какие именно параметры невалидны и почему.

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

Запросы

Получение элементов коллекции

Одним из наиболее частотных запросов является запрос на получение элементов коллекции. Информационные ленты, списки товаров, различные информационные и статистические таблицы и многое другое клиентское приложение отображает посредством обращения к коллекционным ресурсам. Для осуществления этого запроса мы обращаемся к коллекции, используя метод GET и передавая в строке запроса дополнительные параметры. Как мы уже обозначили выше, в качестве ответа мы ожидаем получить массив однородных элементов коллекции и информацию, необходимую для пагинации — подгрузки продолжения списка или же конкретной его страницы. Содержимое выборки может быть особым способом ограничено и отсортировано с помощью передачи дополнительных параметров. О них и пойдёт речь далее.

Постраничная навигация

page — параметр указывает на то, какая страница должна быть отображена. Если этот параметр не передан, то отображается первая страница. Из первого же успешного ответа сервера будет ясно, сколько страниц имеет коллекция при текущих параметрах фильтрации. Если значение превышает максимальное число страниц, то разумнее всего вернуть ошибку 404 Not found.

perPage — указывает на желаемое число элементов на странице. Как правило, API имеет собственное значение по умолчанию, которое возвращает в качестве поля perPage в секции pagination, но в ряде случаев позволяет увеличивать это значение до разумных пределов, предоставив максимальное значение maxPerPage:

Сортировка результатов

Зачастую результаты выборки требуется упорядочить по возрастанию или убыванию значений определенных полей, которые поддерживают сравнительную (для числовых полей) или алфавитную (для строковых полей) сортировку. Например, нам нужно упорядочить список пользователей по имени или товары по цене. Помимо этого мы можем задать направление сортировки от A до Я или в обратном направлении, причём разное для разных полей.

sortBy — существует несколько подходов к передаче данных о сложной сортировке в GET параметрах. Здесь необходимо четко указать порядок сортировки и направление.

В некоторых API это предлагается сделать в виде строки:

В других вариантах предлагается использовать массив:

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

Простая фильтрация по значению

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

Усложнённые варианты фильтрации

Многие интерфейсы требуют более сложной системы фильтрации и поиска. Перечислю основные и наиболее часто встречаемые варианты фильтрации.

Фильтрация по верхней и нижней границе с использованием операторов сравнения from (больше или равно), higher (больше), to (меньше или равно), lower (меньше). Применяется к полям, значения которых поддаются ранжированию.

Фильтрация по нескольким возможным значениям из списка. Применяется к полям, набор возможных значений которых ограничен, например, фильтр по нескольким статусам:

Фильтрация по частичному совпадению строки. Применяется к полям, содержащим текстовые данные или данные, которые могут быть приравнены к текстовым, например, числовые артикулы товаров, номера телефонов и т. д.

Именованные фильтры

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

Именованные фильтры могут также иметь свои параметры.

В этом подразделе я постарался рассказать о наиболее популярных вариантах и способах получения требуемой выборки. Скорее всего, в вашей практике наберется намного больше примеров и нюансов касаемо этой темы. Если у вас есть, чем дополнить мой материал, я буду только рад. Тем временем пост уже разросся до солидных масштабов, так что другие виды запросов мы разберём в следующем приближении.

За перевод материала выражаем благодарность международной IT-компании Noveo.

СОБЫТИЙНО УПРАВЛЯЕМОЕ ПРОГРАММИРОВАНИЕ

Рассмотрим простую и естественную модель событийно управляемого и визуального программирования, характерную для Delphi. В типовой модели у приложения три составляющие: визуальная, системная и обработчики событий (рис.1).

Рис. 1. Составляющие событийно управляемого программирования.

Визуальная составляющая задает образ на экране, с которым будет работать пользователь, т. е. визуальная составляющая определяет интерфейс пользователя. Большинство элементов интерфейса (кнопки, окна, списки и др.) стандартизированы. Поэтому в разных средах разработки (Visual Basic, Visual C++, Delphi и др.) визуальный инструментарий содержит одни и те же элементы интерфейса (элементы управления).

Элементы управления являются объектами. Их свойства и поведение определяются полями и методами соответствующих базовых классов. Классы, порождающие интерфейсные элементы управления, в Delphi называют компонентами. Все визуальные компоненты находятся в библиотеке визуальных компонентов Delphi VCL (Visual Component Library). Кроме визуальных компонентов в этой библиотеке есть невизуальные компоненты, не имеющие образа на экране монитора.

Пользователь – возмутитель спокойствия в мире объектов. Он нажимает на кнопки, выбирает элементы списков, печатает тексты в окнах редактирования. Каждому его действию соответствует некоторое событие. Системная составляющая определяет тип и параметры события и формирует сообщение объекту, с которым связано событие. Иначе говоря, системная составляющая находит нужный объект и запускает соответствующий обработчик события, т. е. соответствующий метод данного объекта. В обработке события программист может предусмотреть самые разные действия: изменение свойств объектов, добавление или удаление интерфейсных объектов и т. д.

Таким образом, чтобы создать приложение, необходимо выполнить две вещи: разработать с помощью визуального инструментария интерфейс пользователя и написать реакции на действия пользователя, т. е. для каждого возможного события написать обрабатывающий его метод. В большинстве приложений нет необходимости программировать системную составляющую. Кроме того, такое программирование часто требует владения функциями Windows API (функции из открытых библиотек Windows).

WINDOWS-ПРИЛОЖЕНИЕ

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

Основным объектом объектно-ориентированной операционной системы Windows является окно. В дополнение к обычным свойствам объекта оно имеет графический образ на экране дисплея, с которым взаимодействует пользователь. Параметры Windows-окна определяют такие свойства, как тип, размер, положение на экране и т. д. В многозадачной и многооконной операционной системе Windows одновременно можно запустить несколько приложений, с каждым из которых может быть связано несколько окон. В каждом приложении имеется, как минимум, одно окно.

События, возникающие в процессе работы компьютера (инициированные пользователем или связанные с посылкой сообщений от одного приложения к другому, от одного окна к другому того же приложения), приводят к возникновению сообщений, из которых операционная система (Windows) организует системную очередь сообщений. Далее сообщения распределяются по приложениям и создаётся для каждого приложения своя очередь. В этой очереди группируются сообщения от разнообразных источников: мыши, клавиатуры, таймера, других приложений и от самой операционной системы. В этой схеме есть исключения, так как некоторые сообщения напрямую направляются окну, например, сообщение WM_DESTROY, уведомляющее о закрытии данного окна.

Windows накладывает довольно жесткие ограничения на структуру приложений — каждое имеет главную процедуру (в Delphi это программа-проект), одинаково устроенную для всех приложений. Главная процедура начинает работу с регистрации класса окна приложения, затем создает и рисует на экране главное окно и, возможно, другие окна. После создания объектов-окон, связанных с приложением, запускается цикл обработки очереди сообщений приложения, который иногда называют основным циклом обработки сообщений.

Мастер Йода рекомендует:  Начинающим C# программистам 5 полезных советов, которые сделают ваш код чище

СРЕДА ПРОГРАММИРОВАНИЯ

Интегрированная среда разработки приложений в Delphi называется IDE (Integrated Development Environment). Под этим шикарным названием скрывается целая коллекция окон, меню и программ, которые позволяют проектировать интерфейс, связывать код с каждым экранным элементом и полностью отлаживать приложение внутри Delphi.

При входе в IDE стандартно появляются 4 окна: главное окно (рис.2), окно инспектора объектов (Object Inspector), окно форм (Form Designer) и окно редактора кода (Code Editor).

Рис. 2. Главное окно IDE.

Главное окно является управляющим центром IDE. Оно управляет файлами, включаемыми в приложение, и выполняет всю работу с их сопровождением, компиляцией и отладкой. Оно состоит из трех отдельных элементов: панель меню (Menubar), панель инструментов (Speedbar) и палитру компонентов (Component Palette).

Окно инспектора объектов, оформлено в виде двухстраничного блокнота (рис.3). Это окно используется для настройки компонента или формы. Первая страница используется для настройки свойств (Properties), вторая – для настройки событий (Events).

Форма является контейнером интерфейсных элементов. Окно форм, (проектировщик форм, Form Designer) используется в процессе разработки интерфейса (рис. 4). Вместе с инспектором объектов проектировщик форм позволяет добавлять компоненты в форму, модифицировать их, связывать обработчики событий с программным кодом на Object Pascal, используя окно редактора кода.


Рис. 4. Окно проектировщика форм.

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

Окно редактора кода (Code Editor, рис.5 справа) позволяет редактировать коды всех модулей (программных единиц), входящих в разрабатываемое приложение. Это окно оформлено в виде многостраничного блокнота. Каждая страница отображает код той или иной программной единицы, входящей в приложение. С помощью проектировщика форм и инспектора объектов представляются все виды частей “фасада” приложения, но без редактора кода нельзя связать эти части в единое целое.

Рис. 5. Окно редактора кода и окно Code Explorer.

По умолчанию слева от редактора кода находится окно Code Explorer (рис. 5). Оно используется для поиска в редакторе кода какого-либо программного элемента: типа, класса, метода и т.д. Это окно можно выделить в самостоятельное и перенести в другое место.

IDE Delphi обладает большой гибкостью в настройке рабочей среды. Для настройки используется диалоговое окно Environment Options, которое выбирается, раскрывая пункты меню ToolsOptions.

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰).

Папиллярные узоры пальцев рук — маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни.

Опора деревянной одностоечной и способы укрепление угловых опор: Опоры ВЛ — конструкции, предназначен­ные для поддерживания проводов на необходимой высоте над землей, водой.

Механическое удерживание земляных масс: Механическое удерживание земляных масс на склоне обеспечивают контрфорсными сооружениями различных конструкций.

HTML-элементы управления и серверные элементы управления

HTML-элементы управления и серверные элементы управления

Еще одной новинкой технологии ASP.NET является использование серверных элементов управления. Серверный элемент управления кодируется в Web-странице, а все его события и свойства обрабатываются Web-сервером. Серверные элементы управления аналогичны HTML-элементам управления, но обладают существенными преимуществами.

Любому разработчику, которому приходилось создавать Web-страницу с формой ввода данных, уже известны HTML-элементы управления. Для программирования формы ввода данных используется элемент FORM вместе с несколькими элементами INPUT, например для создания текстового поля, списка или флажка, как показано ниже.

Элемент INPUT также доступен в технологии ASP.NET, но для работы с его содержимым требуется создать клиентский или серверный сценарий. В рассматриваемой бизнес-ситуации поставлена задача обеспечить полную совместимость созданного приложения со всеми типами Web-броузеров. При использовании клиентского сценария всегда существует вероятность, что какой-то Web-броузер не поддерживает данный сценарий либо выполнение сценариев отключено по соображениям безопасности. Для исключения этих проблем и предназначены серверные элементы управления.

Еще один интересный аспект использования серверных элементов управления связан с технологией ActiveX. Эта технология основана на использовании «толстого» клиента. («Толстый» клиент — это компьютер с богатыми функциональными возможностями и ресурсами, которые часто избыточны с точки зрения сетевых вычислений. — Прим.ред.) По причинам, полное описание которых выходит за рамки данной книги, использование вставленных в Web-страницу элементов управления ActiveX, которыми можно управлять через Internet, было крайне неудачной идеей. В отличие от элемента управления ActiveX, серверный элемент управления не содержит никакого кода, который выполняется на клиентской стороне. Клиент получает только HTML-код, а все операции взаимодействия с пользователям выполняются Web-сервером после получения соответствующего запроса от пользователя («posting back»). Далее на примере объекта DataGrid показан способ применения серверного элемента управления, который принимает набор данных, обрабатывает его и создает HTML-таблицу, которую можно отобразить в любом Web-броузере. Следует признать, что она несколько отличается от стандартной HTML-таблицы с данными.

Серверные элементы управления можно создавать с помощью интегрированной среды разработки Visual Studio .NET.

Завершая сравнение HTML-элементов управления и серверных элементов управления, рассмотрим приведенный ниже фрагмент кода ASP.NET, предназначенного для представления серверного элемента управления, а именно текстового поля txtName.

Этот серверный элемент управления выполняет точно ту же задачу, которую выполняет HTML-элемент управления из приведенного фрагмента кода. Единственным отличием является то, что это текстовое поле обрабатывается Web-сервером.

Клиент-серверная архитектура: особенности взаимодействия

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

Архитектура «Клиент-Сервер» представляет собой взаимодействие структурных компонентов в сети на основе определенных принципов организации данной сети, где структурными компонентами являются сервер и узлы-поставщики определенных специализированных функций (сервисов), а также клиенты, которые пользуются данным сервисом. Специфические функции принято делить на три группы на основе решения определенных задач:

  • функции ввода и представления данных предназначены для взаимодействия пользователя с системой;
  • прикладные функции — для каждой предметной области имеется собственный набор;
  • функции управления ресурсами предназначены для управления файловой системой, различными базами данных и прочими компонентами.

Автономная система, например, компьютер без сетевого подключения, представляет компоненты представления, прикладного назначения и управления на различных уровнях. Такого рода уровнями считаются операционная система, прикладное и служебное программное обеспечение, различные утилиты. Точно так же и в сети представлены все вышеуказанные компоненты. Главное – правильно обеспечить сетевое взаимодействие между этими составляющими.

Клиент-серверная архитектура наиболее часто используется для создания корпоративных баз данных, в которых информация не только хранится, но и периодически поддается обработке различными методами. Именно база данных является главным элементом любой корпоративной информационной системы, а на сервере располагается ядро этой базы. Так, на сервере происходят наиболее сложные операции, касающиеся ввода, хранения, обработки и модификации данных. Когда пользователь (клиент) обращается к базе данных (серверу), происходит обработка запроса: непосредственно обращение к базе данных и возврат ответа (результата обработки). Результат обработки – это сообщение сети об успешном проведении операции или ошибке. Серверные компьютеры могут обрабатывать одновременно обращение нескольких клиентов к одному и тому же файлу. Такая работа и передача данных по сети позволяет ускорить работу используемых приложений.

Данная архитектура используется для доступа к различным ресурсам с использованием сетевых технологий: Web-серверы, серверы приложений, серверы баз данных, почтовые серверы, файрволы, прокси-серверы. Разработка клиент-серверных приложений позволяет повысить безопасность, надежность и производительность используемых приложений и сети в целом. Наиболее часто клиент-серверные приложения используются для автоматизации бизнеса.

Введение в серверную часть

Добро пожаловать на курс для начинающих по программированию серверной части сайта! В этой первой статье мы рассмотрим программирование на стороне сервера с высокого уровня, отвечая на такие вопросы, как «что это?», «как это отличается от программирования на стороне клиента?», и почему это так полезно? После прочтения этой статьи вы поймете дополнительные возможности, доступные веб-сайтам посредством программирования на стороне сервера.

Перед стартом: Базовая компьютерная грамотность. Базовое понимание, что такое веб-сервер.
Цель: Ознакомиться с тем, что такое программирование серверной части, на что оно способно и чем отличается от программирования клиентской части.

Большинство крупных веб-сайтов используют программирование серверной части чтобы динамично отображать различные данные при необходимости, в основном взятые из базы данных, располагающейся на сервере и отправляемые клиенту для отображения через некоторый код (например, HTML и JavaScript).

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

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

В современном мире веб-разработки настоятельно рекомендуется узнать о разработке на стороне сервера.

Что такое программирование серверной части сайта?

Веб браузеры взаимодействуют с веб-серверами при помощи гипертекстового транспортного протокола (HTTP). Когда вы нажимаете на ссылку на веб-странице, заполняете форму или запускаете поиск, HTTP запрос отправляется из вашего браузера на целевой сервер.

Запрос включает в себя URL, определяющий затронутый ресурс, метод, определяющий требуемое действие (например, получить, удалить или опубликовать ресурс) и может включать дополнительную информацию, закодированную в параметрах URL (пары поле-значение, оправленные как строка запроса), как POST запрос (данные, отправленные методом HTTP POST), или в куки-файлах.

Веб серверы ожидают сообщений с клиентскими запросами, обрабатывают их по прибытию и отвечают веб-браузеру при помощи ответного HTTP сообщения. Ответ содержит строку состояния, показывающую, был ли запрос успешным, или нет (например, «HTTP/1.1 200 OK» в случае успеха.

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

Статические сайты

Схема ниже показывает базовую архитектуру веб-сервера для статического сайта (статический сайт — это тот, который возвращает одно и то же жестко закодированное содержимое с сервера всякий раз, когда запрашивается конкретный ресурс). Когда пользователь хочет перейти на страницу, браузер отправляет HTTP-запрос «GET» с указанием его URL.

Сервер извлекает запрошенный документ из своей файловой системы и возвращает HTTP-ответ, содержащий документ и успешный статус (обычно 200 OK). Если файл не может быть извлечен по каким-либо причинам, возвращается статус ошибки (смотри ошибки клиента и ошибки сервера).

Динамические сайты

Динамический веб-сайт — это тот, где часть содержимого ответа генерируется динамически только при необходимости. На динамическом веб-сайте HTML-страницы обычно создаются путем вставки данных из базы данных в заполнители в HTML-шаблонах (это гораздо более эффективный способ хранения большого количества контента, чем использование статических сайтов).

Динамический сайт может возвращать разные данные для URL-адреса на основе информации, предоставленной пользователем или сохраненными настройками, и может выполнять другие операции как часть возврата ответа (например, отправку уведомлений).

Большая часть кода для поддержки динамического веб-сайта должна выполняться на сервере. Создание этого кода известно, как «программирование серверной части» (или иногда «программирование бэкенда»).

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

Запросы статических ресурсов обрабатываются так же, как и для статических сайтов (статические ресурсы – это любые файлы, которые не меняются, обычно это: CSS, JavaScript, изображения, предварительно созданные PDF-файлы и прочее).

Запросы динамических данных отправляются (2) в код серверной части (показано на диаграмме как Веб-приложение). Для «динамических запросов» сервер интерпретирует запрос, читает необходимую информацию из базы данных (3), комбинирует извлеченные данные с шаблонами HTML и возвращает ответ, содержащий сгенерированный HTML (5, 6).

Одинаково ли программирование серверной части и клиентской?

Теперь обратим внимание на код, задействованный в серверной части и клиентской части. В каждом случае код существенно различается:

  • Они имеют различные цели и назначение.
  • Как правило, они не используют одни и те же языки программирования (исключение составляет JavaScript, который можно использовать на стороне сервера и клиента).
  • Они выполняются в разных средах операционной системы.

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

Код клиентской части написан с использованием HTML, CSS и JavaScript — он запускается в веб-браузере и практически не имеет доступа к базовой операционной системе (включая ограниченный доступ к файловой системе).

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

Код серверной части может быть написан на любом количестве языков программирования – примеры популярных языков серверной части включают в себя PHP, Python, Ruby,C# и NodeJS(JavaScript). Код серверной части имеет полный доступ к операционной системе сервера, и разработчик может выбрать какой язык программирования (и какую версию) он хотел бы использовать.

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

И снова, поскольку и клиентская и серверная части используют фреймворки, области очень разные и, следовательно, фреймворки тоже разные. Фреймворки клиентской части упрощают вёрстку и представление данных, тогда как фреймворки серверной части обеспечивают много «обычного» функционала веб-сервера, который вы возможно в противном случае должны были осуществлять самостоятельно (например, поддержка сессий, поддержка пользователей и аутентификация, простой доступ к базе данных, шаблонам библиотек, и т.д.).

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

И наоборот, вы практически никогда не посмотрите в сторону написания кода серверной части веб-приложения без фреймворка: осуществление жизненно важной функции, такой как HTTP сервер действительно сложно сделать с нуля скажем на Python, но веб-фреймворки для Python, такие как Django обеспечивают это из коробки вместе с другими полезными инструментами.

Что можно сделать в серверной части?

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

Компании, такие как Amazon, используют программирование серверной части для построения исследовательских результатов для товаров, формирования целевого предложения, основанного на предпочтениях клиента и предыдущих покупках, упрощения заказов и т.д. Банки используют программирование серверной части, чтобы хранить учетную информацию и позволять только авторизованным пользователям просматривать и совершать транзакции. Другие сервисы, такие как Facebook, Twitter, Instagram и Wikipedia используют бэкэнд, чтобы выделять, распространять и контролировать доступ к интересному контенту.

Некоторые типичные применения и выгоды бэкэнда перечислены ниже. Вы заметите, что есть некоторое пересечение!

Эффективное хранение и доставка информации

Представьте, сколько товаров доступно на Amazon и представьте, сколько постов было написано на Facebook? Создание статической страницы для каждого товара или поста было бы абсолютно неэффективным.

Программирование серверной части позволяет вместо этого хранить информацию в базе данных и динамически создавать, и возвращать HTML и другие типы файлов (например, PDF, изображения, и т.д.). Также есть возможность просто вернуть данные (JSON, XML, и т.д.) для отображения используя подходящий фреймворк клиентской части (это уменьшает загрузку процессора на сервере и количество передаваемых данных.

Сервер не ограничен в отправке информации из баз данных и может вместо этого возвращать результат инструментов программного обеспечения или данные из сервисов коммуникации. Контент даже может быть целевым относительно устройства клиента, который его получает.

Из-за того, что информация находится в базе данных, её также можно легко передать и обновить через другие бизнес системы (например, отслеживание).


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

  1. Зайдите на Amazon или другой интернет-магазин.
  2. Введите в поиск несколько ключевых слов и заметьте, как структура страницы не изменилась, тогда как результаты изменились.
  3. Откройте два или три разных товара. Заметьте, что они имеют схожую структуру и внешний вид, но содержимое для разных товаров было вставлено из базы данных.

Для обычного поиска (например, «рыба») вы можете увидеть буквально миллионы найденных значений. Использование базы данных позволяет им храниться и передаваться эффективно, и это позволяет контролировать представление информации всего в одном месте.

Настраиваемый пользовательский опыт взаимодействия

Серверы могут хранить и использовать информацию о клиентах чтобы поставлять удобный и сделанный индивидуально пользовательский опыт взаимодействия. Например, многие сайты хранят данные кредитных карт, чтобы не нужно было вводить их повторно. Сайты наподобие Google Maps используют домашний адрес и текущее местоположение для предоставления информации о маршруте и выделяя местные учреждения в результатах поиска.

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

Внимание: Зайдите в Google Maps как анонимный пользователь, выберете кнопку «Как добраться» и введите начальную и конечную точки для проезда. Теперь войдите в систему используя ваш гугл аккаунт, если он у вас есть (информация об этом появляется на панели внизу, когда вы выбираете маршрут). Веб-сайт теперь позволит выбрать местоположение дома и работы и начальные и конечные точки (или сохранить эти детали, если вы их еще не вводили).

Контролируемый доступ к контенту

Программирование серверной части позволяет сайтам ограничивать доступ авторизованным пользователям и предоставлять только ту информацию, которую пользователю разрешено видеть.

  • Социальные сети, такие как Facebook позволяют пользователям полностью контролировать свои данные, но только разрешать своим друзьям просматривать и комментировать их. Пользователь определяет, кто может просматривать его данные и более того, чьи данные появляются на их стене. Авторизация — центральная часть опыта взаимодействия.
  • Сайт, на котором вы находитесь прямо сейчас контролирует доступ к контенту: статьи видны всем, но только авторизованные пользователи могут редактировать контент. Чтобы попробовать это, нажмите на кнопку «Редактировать» вверху страницы, и, если вы авторизованы, вы увидите редакторский интерфейс, если нет — вас отправит на страницу авторизации.

Внимание: Рассмотрим другие реальные примеры, где доступ к контенту контролируется. Например, что вы можете увидеть, если зайдете на сайт вашего банка? Авторизуйтесь через вашу учетную запись и какую дополнительную информацию вы можете просматривать и редактировать? Что за информацию вы можете увидеть, которую может редактировать только банк?

Хранение информации о сессии/состоянии

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

Внимание: Посетите новостной сайт, у которого есть подписка и откройте ветку тегов (например, The Age). Продолжайте посещать сайт в течении нескольких часов/дней. В итоге вас начнет перенаправлять на страницы, объясняющие, как подписаться и статьи станут вам недоступны. Эта информация является примером сессии, сохраненной в куки-файлах.

Уведомления и средства связи

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

Вот несколько примеров:

  • Facebook или Twitter отправляет уведомления по электронной почте и смс-сообщения, чтобы уведомить вас о новых разговорах.
  • Регулярно отправляет письма на электронную почту, предлагающие товары, похожие на те, которые уже были куплены или просмотрены, которые могут вас заинтересовать.
  • Веб-сервер может посылать предупреждения администратору сайта, предупреждая его о том, что на сервере заканчивается память или о подозрительной активности пользователя.

Внимание: Самый распространенный вид уведомлений – это «подтверждение регистрации». Возьмите почти любой интересующий вас большой сайт (Google, Amazon, Instagram, и т.д.) и создайте новую учетную запись используя ваш адрес электронной почты. Вы вскоре получите письмо, подтверждающую вашу регистрацию или с необходимой информацией для активации вашей учетной записи.

Анализ данных

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

Например, и Amazon и Google рекламируют товары на основании предыдущих поисков (и покупок).

Внимание: Если вы пользуетесь Facebook, зайдите на вашу стену и посмотрите на ряд постов. Заметьте, что некоторые посты не идут по порядку: в частности, посты с большим количеством «лайков» часто находятся выше по списку, чем остальные посты. Также взгляните на рекламу, которую вам показывают, вы вероятно увидите рекламу товаров, которые искали на других сайтах. Алгоритм Facebook’а для выделения контента и рекламы может казаться мистикой, но очевидно, что он зависит от ваших лайков и запросов поиска!

Подведение итогов

Поздравляем, вы дошли до конца первой статьи о программировании серверной части.

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

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

В следующей статье мы поможем вам выбрать лучший фреймворк для вашего первого сайта; затем мы изучим несколько основных взаимодействий с клиентской частью более подробно.

Основы создания серверных элементов управления. Рисование.

Основы создания серверных элементов управления. Рисование.

Концепция серверных элементов управления, предложенная Microsoft в ASP.NET, поднимает возможности веб программистов на невиданную доселе высоту. Теперь можно забыть о кропотливом создании отдельных кусков сешанного html/asp кода для решения типовых задач (например вывода данных в таблицу с возможностью сортировки и постраничного вывода) и копирования этих кусков кода в нужные места страниц. Достаточно всего лишь один раз создать класс серверного элемента управления, реализующий данную функциональность и скомпилировать его в сборку и можно использовать получившийся сэлемент управления в любых своих проектах (и даже распространять его дабы и другие программисты могли насладиться его функциональностью :)).

Что же такое серверный элемент управления с точки зрения ASP.NET программиста? Это класс, родителем которого (явным или неявным) является класс System.Web.UI.Control (на самом деле это несколько не так, но для веб программиста данного определения хватит с головой). Данный класс представляет базовую функциональность для элемента управления -например размещение в коллекции серверных элементов управления веб формы и отрисовку. Также он предоставляет функциональность для своего добавления в панель элементов управления и работы в дизайн режиме.

Для создания видимых сервеных элементов управления в основном имспользуется класс System.Web.UI.WebControls.WebControl — наследник класса System.Web.Ui.Control. В этот класс добавлено множество свойств для визуального представления серверного элемента управления (например Font, CssClass, etc), а также добавлена дополнительная функциональность (в том числе и для отрисовки).

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

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

Мастер Йода рекомендует:  Представлены результаты опроса Python Developers Survey 2020

Данный элемент управления представляет собой таблицу, содержащую 3 ячейки для отображения информации о текущей страницы, кнопок для переходов вперед-назад и кнопок для переходов на конкретную страницу. У него есть следующие, нужные при рисовании, свойства:

Свойство Описание
PageSize Размер страницы в строках
RowsTotal Строк всего в источнике данных
CurrentPageIndex Текущий номер страницы
CurrentPageFormat Формат для отображения информации о текущей странице (левая ячейка)

Начнем создавать класс элемента управления с описания этих свойств:

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

Теперь начнем создания нашего элемента управления. И первые пробы проведем на элементе управления, унаследованном от System.Web.UI.Control. Но для начала немного теории.

Класс System.Web.UI.Control использует при отображении элемента управления три метода и одно свойство. Используемое свойство это ClientID — клиентский дентификатор элемента управления, уникальный в пространстве идентификаторов страницы. Методы же следующие:

Метод Описание
public void RenderControl(HtmlTextWriter writer) Проверяет включено ли отображение элемента управления, и если включено — вызывает метод Render
protected virtual void Render(HtmlTextWriter writer) Вызывает метод RenderChildren для отрисовки вложенных элементов управления
protected virtual void RenderChildren(HtmlTextWriter writer) Для каждого элемента управления из коллекции Controls данного элемента управления вызывает его метод RenderControl.

В данной таблице приведено описание функциональности, заложенной в эти методы в классе System.Web.UI.Control. При создании элементов управления, напрямую наследуемых от System.Web.UI.Control, для отрисовки необходимо переопределить метод Render. Сделаем это.

Генерация html кода для серверного элемента управления происходит с помощью вызова методов класса HtmlTextWriter.

Первый пример реализации метода Render можно назвать «решением в лоб» — в нем мы будем рисовать нашу таблицу почти так же, как если бы мы рисовали ее с помощью вызовов Response.Write. Никогда не пишите html код элемента управления таким образом — этот кусок кода приведен только для примера!

Описывать логику работы данного метода я думаю нет смысла — все и так достаточно прозрачно. А вот о чем есть смысл поговорить, так это о том, как правильно использовать класс HtmlTextWriter.

Класс HtmlTextWriter представляет с десяток методов для генерации правильного html кода. Наиболее важные для разработчиков серверных элементов управления методы приведены в таблице:

Метод Описание
public virtual void RenderBeginTag(HtmlTextWriterTag); Записывает открывающий тег html элемента. Тип тега задается из перечисления HtmlTextWriterTag. Также есть возможность задавать html элемент строкой.
public virtual void RenderEndTag(); Записывает закрывающий тег html элемента. Каждый тег, открытый с помощью вызова метода RenderBeginTag, должен быть закрыт с помощью RenderEndTag
public virtual void AddAttribute(. ); Добавляет атрибут в стек. Все добавленные в стек атрибуты присваиваются к первому html элементу, записанному с помощью вызова метода RenderBeginTag.
public virtual void
AddStyleAttribute(. );
Добавляет стилевой атрибут в стек. Все добавленные в стек атрибуты присваиваются к первому html элементу, записанному с помощью вызова метода RenderBeginTag.
public override void Write(. ); Записывает значение передаваемого параметра.

Теперь попробуем переписать наш метод Render используя приведенную выше таблицу. Должно получиться примерно следующее:

Кода стало несколько больше, но преимущества использования данного метода генерации html кода все таки перевешивают. Во первых в результате выполнения этого кода будет получен правильный и «красивый» html код («красивый» в данном контексте означает отформатированный). А во вторых при генерации html кода элементов управления ASP.NET умеет автоматически подставлять вместо класса HtmlTextWriter его наследников в зависимости от установок в секции
файла machine.config. Например если веб форму запрашивает старый браузер, не понимающий HTML 4.0, класс HtmlTextWriter будет подменен классом HtmlTextWriter32 и будет сгенерирован html, полностью соответствующий спецификации HTML 3.2 (например многие стилевые атрибуты будут заменены на подобные по функциональности html элементы, а вместо элемета div будет использован элемент table). Так что старайтесь писать правильно код генерации html и не гонитесь за мнимой быстротой.

Итак элемент управления создан, рисовать он себя умеет, все красиво, все довольны. Но есть одно большое «но» — нет возможности изенить стили выводимого элемента управления — например поменять шрифт или цвет фона. И все это потому, что класс System.Web.UI.Control предназначен для создания невизуальных элементов управления (например элемента title или xml). А для того, чтобы создавать отображаемые элементы цправления, предназначен класс System.Web.UI.WebControl, уже имеющий базовый набор свойств для стилевого оформления элемента управления. А заодно и расширенный набор методов, отвечающих за отрисовку. Рассмотрим эти методы и свойства:

Метод/свойство Описание
public Style ControlStyle Класс, содержащий свойства стилевого оформления элемента управления
public bool ControlStyleCreated Свойство, индикатор того, что стиль элемента управления создан.
protected virtual HtmlTextWriterTag TagKey html тег элемента управления.
protected virtual string TagName Строка — html тег элемента управления. Используется когда нет соответствующего значения из перечисления HtmlTextWriterTag.
protected virtual Style CreateControlStyle(); Метод создания свойства стилевого оформления документа.
public void ApplyStyle(Style s ); Применяет стиль, указанный в параметре, к элементу управления. При этом из стиля s в стиль элемента управления переносятся все непустые значения, переписывая соответствующие значения в стиле элемента управления.
public void MergeStyle(Style s ); Применяет стиль, указанный в параметре, к элементу управления, но при этом не переписывает существующие значения в стиле элемента управления.
protected virtual void AddAttributesToRender(HtmlTextWriter writer ); Добавляет атрибуты и стили из элемента управления в HtmlTextWriter.
public virtual void RenderBeginTag(HtmlTextWriter writer ); Выводит откывающий html тег для элемента управления
protected virtual void RenderContents(HtmlTextWriter writer ); Выводит содержимое элемента управления (без открывающего и закрывающего html тегов)
public virtual void RenderEndTag(HtmlTextWriter writer ); Выводит закрывающий html тег.

Как же WebControl себя рисует с учетом данных нововведений? А достаточно просто — взгляните на код:

Как видно из приведенного кода при создании элемента управления из System.Web.UI.WebControls.WebControl для генерации html кода необходимо в общем случае использовать метод RenderContents, а не метод Render. Также при необходимости нужно пеоеопределить свойства TagKey или TagName (по умолчанию WebControl использует тег ) или методы RenderBeginTag/RenderEndTag.

Попробуем теперь расширить функциональность отображения нашего элемента управления на основе всего вышеизложенного. И внесем в него следующие изменения:

  1. Добавим работу со стилями, специфичными для отображения таблицы.
  2. Добавим стили для каждой из ячеек элемента управления — ячейки информации, ячейки кнопок «вперед-назад» и ячейки навигационных кнопок.

Итак начем со стилей элемента управления. Первым делом необходимо переопределить метод CreateControlStyle:

Теперь необходимо добавить в элемент управления свойства, специфичные для таблицы — CellSpacing, CellPadding и HorizontalAlign. Обратите внимание на то, что эти свойства сохраняются в в свойстве ControlStyle, которое в создаваемом элементе управления имеет тип TableStyle.

Самое интересное во всем этом коде то, что для его отрисовки ничего больше делать не нужно. При вызове метода WebControl.AddAttributesToRender в нем вызывается метод ControlStyle.AddAttributesToRender, который и выводит все введенные данные.

Теперь добавим свойства для стилей ячеек элемента управления. Эти свойства будут иметь тип TableItemStyle:

Обратите внимание на то, как правильно нужно объявлять сложные свойства — всегда делайте их «только для чтения» . И еще раз напоминаю, что в данной статье мы не рассматриваем сохранение состояние между постбеками, поэтому все свойства сохраняются в приватных переменных класса.

Теперь осталось только сгенерировать html код. Для этого необходимо переопределить свойство TagKey и метод RenderContents. Сделаем это:

Приведенный код не очень сильно отличается от кода метода Render, рассмотренного в предыдущем примере. Таких отличий всего 2:

  1. Не вызывается метод для генерации тега table (этот тег генерится в методах RenderBeginTag и RenderEndTag на основании значения свойства TagKey.
  2. При генерации тегов td к ним добавляются соответствующие стили с помощью вызовов их методов AddAttributesToRender.

Все. Последняя (и наиболее правильная) версия рисования серверного элемента управления Pager готова. Конечно есть и еще один вариант создания этого метода — с помощью заполнения коллекции Controls элемента управления, но это тема для отдельной статьи.

Основы создания серверных элементов управления. События.


  1. Общие методы элементов управления.
  2. Общие события элементов правления.
  3. Последовательность событий при работе
  4. Создание процедуры обработки события

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

Общие методы элементов управления.

Add – позволяет добавить элемент управления во время выполнения программы.

SetFocus – устанавливает фокус на вызывавшем этот метод элементе управления. Часто применяется в программах обработки ошибок.

Clear — метод позволяет удалить все объекты из объекта или семейства .Для элементов MultiPage и Tabstrip метод позволяет удалить все вкладки. Для элементов управления listBox и ComboBox метод позволяет удалить все вхождения в список. В семействе Controls метод позволяет удалить элементы управления, созданные во время выполнения с помощью метода Add .

Copy — метод позволяет скопировать содержимое объекта в буфер обмена.

Cut — метод позволяет скопировать выделенное содержимое объекта в буфер обмена.После выполнения копирования выделенные в объекте данные удаляются.

DropDown – метод позволяет отобразить раскрывающийся список объекта Combobox .

Private sub commandbutton1_ click()

ComboBox 1. DropDown

GetFormat – метод позволяет определить формат данных , хранящихся в объекте DataObject .Параметр format содержит целочисленное или строковое значение, характеризующее определенный формат, который мог бы храниться в объекте DataObject . Если указанный формат имеется , то параметру Boolean присваивается значение True . параметр format может принимать следующие значения:

Строка или любое число, отличное от 1 ,- пользовательский формат

DataObject , определенный с помощью метода SetText .

Paste — метод позволяет вставить в объект данные, находящиеся в буфере обмена.

UndoAction — метод позволяет отменить последнее выполненное действие.

RedoAction — метод позволяет восстановить последнее отмененное действие

Move имеет два синтаксиса

Move ( [ left [, Top [, Width [, Height [, Layout ]]]]])- для формы или элемента управления

Move ( x , y ) – для семейства Controls .

Метод Move позволяет изменить положение и размеры формы или элементов управления , находящихся в поле формы. Если метод применяется к семейству Controls , то выполняется изменение положения и размеров всех элементов управления, входящих в состав семейства. Параметр Left – указывает на новое положение левой границы объекта, Top – на положение верхней границы, Width – на новую ширину, Height – на новую высоту. Параметр Layout указывает на необходимость генерации события LayOut для родительского элемента управлени я( значение по умолчанию – False — событие генерируется). Параметры X , Y содержат величину изменения горизонтальной и вертикальной координат каждого объекта, входящего в состав семейства Controls .

Remove ( collectionindex ) – метод позволяет удалить объект из семейства, формы, рамки и вкладки. Параметр collectionindex имеет строковое или целочисленное значение, определяющее имя или индекс объекта. Индекс указывается при удалении элемента семейства. Метод позволяет удалять только те объекты, которые были созданы динамически во время выполнения программы.

RemoveItem ( index ) – метод позволяет удалить из списка строку с индексом index . Первая строка списка имеет индекс 0, вторая -1 и т.д. Если строка была удалена , метод возвращает значение true .

Repaint – метод обновляет( перерисовывает) экран после изменения формы или вкладки. Этот метод требует явного использования только в ситуациях, когда отображение сделанных изменений важны и нет возможности дождаться , пока система сама автоматически внесет изменения. Если изменения были внесены и экран был перерисован , метод возвращает значение true .

Zorder ([ zposition ]) – помещает объект до или после всех пересекающихся с ним объектов. Параметр Zpozition указывает на слой , в котором должен размещаться объект: fmTop (значение по умолчанию) – объект размещается в самом верхнем слое, Fmbottom — объект размещается в самом нижнем слое.

Общие события элементов правления.

В отличи и от свойств и методов инициализация события выполняется путем вызова уже соответствующей процедуры, которая определена только для этого модуля- в ее заголовке всегда используется слово Private . Имя процедуры, определяющей событие, состоит из служебного слова Private , имени объекта object , генерирующего событие event и списка аргументов arglist :

Private Sub object_ event [ ( arglist )]

AfterUpdate — происходит всякий раз после того, как пользователь изменит данные в элементе управления.Причем оно выполняется для элементов управления независимо от того, является ли они присоединительными или нет.Событие AfterUpdate происходит после события BeforeUpdate

и до события Exit текущего элемента управления.

BeforeUpdate — происходит непосредственно перед изменением данных вэлементе управления.

Click – происходит, когда пользователь выбирает элемент управления с помощью одинарного щелчка кнопкой мыши.

DbClick – происходит, когда пользователь выбирает элемент управления с помощью двойного щелчка кнопкой мыши.

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

Событие происходит только при нажатии:

Клавиши Ctrl в сочетании с любой клавишей стандартного алфавита или специального символа

Событие KeyPress не происходит при нажатии следующих клавиш:

Клавиш управления курсором

Tab , Enter , Delete

Change – происходит при изменении значения свойства Value элемента управления.

Это событие может происходить в следующих случаях:

При щелчке мышью на переключателе или выключателе

При вводе нового текста в текстовое поле или выборе нового элемента в списке

При выборе другой вкладки в наборе вкладок или другой страницы в наборе страниц

При перемещении бегунка полосы прокрутки

Activate – происходит, когда элемент получает фоку с( окно становится активным).

AddControl – когда в форму, рамку или на вкладку добавляется новый элемент управления.

Deactivate – происходит, когда форма теряет фокус.

Enter и Exit – происходит перед тем, как элемент управления получает фокус от другого элемента управления той же самой формы.

Error – используется при уведомление об ошибке.

Zoom -событие генерируется при изменении масштаба( значения свойства Zoom )

Terminate – Событие генерируется при выгрузке объекта из памяти или при удалении связи между объектной переменной и областью памяти , где расположен объект.

SpinUp – событие генерируется при нажатии верхней или правой кнопки в элементе управления SpinButton ( счетчик).

SpinDown – событие генерируется при нажатии верхней или правой кнопки в элементе управления SpinButton ( счетчик).

Scroll – Событие генерируется при перемещении бегунка полосы прокрутки формы.

RemoveControl -событие генерируется при динамическом удалении объекта из родительского объекта-контейнера.

Layout -событие генерируется при изменении текущей формы элемента управления.

KeyDown – событие генерируется при нажатии на клавишу.Процедура обработки события имеет два параметра KeyCode и Shift , которые передают впроцедуру соответственно код клавиши и состояние управляющих клавиш Alt , Ctrl , Shift . Параметр Shift может принимать следующие значения:

Fmsiftmask -нажата клавиша shift

Fmctrlmask -нажата клавиша ctrl

fmAltmask -нажата клавиша Alt

Например комбинация Fmsiftmask + Fmctrlmask + fmAltmask указывает на одновременное нажатие клавиш Alt , Ctrl , Shift .

KeyUp — событие генерируется , когда пользователь отпускает клавишу.Событие имеет те же параметры , что и событие KeyDown .

Initialize – событие генерируется сразу после загрузки объекта , перед его визуализацией.

DropButtonClick – событие генерируется при каждом раскрытии или сворачивании раскрывающего списка.

Рассмотри синтаксис процедур обработки событий, генерируемых нажатием кнопки мыши и перемещением указателя мыши и связанных с элементами управления.

MouseDown — при нажатии кнопкой мыши.

MouseUp – при отпускании кнопки мыши.

MouseMove – при перемещении указателя мыши.

Private Sub object_ MouseDown ( ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)


Private Sub object_ MouseUp ( ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)

Private Sub object_MouseMove ( ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)

Button – возвращает ко д( значение) нажатой кнопки мыши. Допустимые значения:

FmButtonLeft или 1 (левая)

FmButtonRight или 2 (правая)

FmbuttonMiddle или 4 (средняя)

Shift – возвращает код (значение) нажатой на клавиатуре клавиши. Допустимые значения:

fmShiftMask – или 1 ( Shift >)

fmCtrlMask – или 2 ( Ctrl >)

fmAltmask –или 4( Alt >)

X и У – возвращает значение расстояния от левого или от верхнего края формы, рамки или страницы. При событии MouseMove этим расстоянием считается путь в направлении от левого верхнего угла элемента управления по горизонтали или вертикали .

События, связанные с перемещением элемента управления.

BeforeDragOver –пока совершается операция drag-and-drop .

BeforeDropOrPaste – перед завершением операции drag-and-drop .

Private Sub object_BeforeDragOver ( ByVal Cancel As MSForms.ReturnBoolean , ByVal Data As MSForms.DataObject , ByVal X As Single, ByVal Y As Single, ByVal DragState As Long, ByVal Effect As MSForms.ReturnEffect , ByVal Shift As Integer)

Private Sub object_BeforeDropOrPaste ( ByVal Cancel As MSForms.ReturnBoolean , ByVal Action As Long, ByVal Data As MSForms.DataObject , ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms.ReturnEffect , ByVal Shift As Integer)

Cancel – допустимые значения:

False – по умолчанию, элемент обрабатывает событие.

True – приложение обрабатывает событие.

Data – данные перемещаемые во время операции drag-and-drop . Эти данные размещаются в объекте DataOject — это своеобразный аналог буфера обмена, в отличи и от которого в нем допускаются хранить только текстовую информацию.

Х и У – расстояние от левого верхнего угла элемента управления по горизонтали и вертикали.

DragState – устанавливает позицию указателя мыши относительно целевого объекта.

fmDragStateEnter или 0 (указатель мыши внутри целевого эл .у прав .)

fmDragStateLeave или 1 (указатель мыши вне целевого элемента управления)

fmDragStateOver или 2 (указатель мыши в новой позиции. Но остается внутри элемента управления)

Effect – устанавливает операцию, производимую над объектом.

fmDropEffectCopy или 0 (не копировать и не перемещать)

fmDropEffectCopy или 1 (копировать объект)

fmDropEffectMove или 2 (перемещать объект)

fmDropEffectCopyOrMove или 3 (копировать или перемещать объект)

Shift – возвращает код нажатой на клавиатуре клавиши.

Последовательность событий при работе с данными в элементе управления

Enter Change BeforeUpdate AfterUpdate Exit

Последовательность событий при работе с мышью

MouseDown MouseUp Click

При двойном щелчке мышью события возникают в последовательности

MouseDown MouseUp Click DblClick MouseUp

Последовательность событий при работе с клавиатурой

При нажатии клавиши происходит следующая цепочка событий.

Создание процедуры обработки события

Для создания обработчика события можно воспользоваться возможностью VBA автоматически создавать заготовки события.

1.Вберите в списке Object окна программы объект, для которого необходимо создать процедуру обработки события.

2. Выберите в списке Procedure процедуру обработки события.

СОБЫТИЙНО УПРАВЛЯЕМОЕ ПРОГРАММИРОВАНИЕ

Рассмотрим простую и естественную модель событийно управляемого и визуального программирования, характерную для Delphi. В типовой модели у приложения три составляющие: визуальная, системная и обработчики событий (рис.1).

Рис. 1. Составляющие событийно управляемого программирования.

Визуальная составляющая задает образ на экране, с которым будет работать пользователь, т. е. визуальная составляющая определяет интерфейс пользователя. Большинство элементов интерфейса (кнопки, окна, списки и др.) стандартизированы. Поэтому в разных средах разработки (Visual Basic, Visual C++, Delphi и др.) визуальный инструментарий содержит одни и те же элементы интерфейса (элементы управления).

Элементы управления являются объектами. Их свойства и поведение определяются полями и методами соответствующих базовых классов. Классы, порождающие интерфейсные элементы управления, в Delphi называют компонентами. Все визуальные компоненты находятся в библиотеке визуальных компонентов Delphi VCL (Visual Component Library). Кроме визуальных компонентов в этой библиотеке есть невизуальные компоненты, не имеющие образа на экране монитора.

Пользователь – возмутитель спокойствия в мире объектов. Он нажимает на кнопки, выбирает элементы списков, печатает тексты в окнах редактирования. Каждому его действию соответствует некоторое событие. Системная составляющая определяет тип и параметры события и формирует сообщение объекту, с которым связано событие. Иначе говоря, системная составляющая находит нужный объект и запускает соответствующий обработчик события, т. е. соответствующий метод данного объекта. В обработке события программист может предусмотреть самые разные действия: изменение свойств объектов, добавление или удаление интерфейсных объектов и т. д.

Таким образом, чтобы создать приложение, необходимо выполнить две вещи: разработать с помощью визуального инструментария интерфейс пользователя и написать реакции на действия пользователя, т. е. для каждого возможного события написать обрабатывающий его метод. В большинстве приложений нет необходимости программировать системную составляющую. Кроме того, такое программирование часто требует владения функциями Windows API (функции из открытых библиотек Windows).

WINDOWS-ПРИЛОЖЕНИЕ

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

Основным объектом объектно-ориентированной операционной системы Windows является окно. В дополнение к обычным свойствам объекта оно имеет графический образ на экране дисплея, с которым взаимодействует пользователь. Параметры Windows-окна определяют такие свойства, как тип, размер, положение на экране и т. д. В многозадачной и многооконной операционной системе Windows одновременно можно запустить несколько приложений, с каждым из которых может быть связано несколько окон. В каждом приложении имеется, как минимум, одно окно.

События, возникающие в процессе работы компьютера (инициированные пользователем или связанные с посылкой сообщений от одного приложения к другому, от одного окна к другому того же приложения), приводят к возникновению сообщений, из которых операционная система (Windows) организует системную очередь сообщений. Далее сообщения распределяются по приложениям и создаётся для каждого приложения своя очередь. В этой очереди группируются сообщения от разнообразных источников: мыши, клавиатуры, таймера, других приложений и от самой операционной системы. В этой схеме есть исключения, так как некоторые сообщения напрямую направляются окну, например, сообщение WM_DESTROY, уведомляющее о закрытии данного окна.

Windows накладывает довольно жесткие ограничения на структуру приложений — каждое имеет главную процедуру (в Delphi это программа-проект), одинаково устроенную для всех приложений. Главная процедура начинает работу с регистрации класса окна приложения, затем создает и рисует на экране главное окно и, возможно, другие окна. После создания объектов-окон, связанных с приложением, запускается цикл обработки очереди сообщений приложения, который иногда называют основным циклом обработки сообщений.

СРЕДА ПРОГРАММИРОВАНИЯ

Интегрированная среда разработки приложений в Delphi называется IDE (Integrated Development Environment). Под этим шикарным названием скрывается целая коллекция окон, меню и программ, которые позволяют проектировать интерфейс, связывать код с каждым экранным элементом и полностью отлаживать приложение внутри Delphi.

При входе в IDE стандартно появляются 4 окна: главное окно (рис.2), окно инспектора объектов (Object Inspector), окно форм (Form Designer) и окно редактора кода (Code Editor).

Рис. 2. Главное окно IDE.

Главное окно является управляющим центром IDE. Оно управляет файлами, включаемыми в приложение, и выполняет всю работу с их сопровождением, компиляцией и отладкой. Оно состоит из трех отдельных элементов: панель меню (Menubar), панель инструментов (Speedbar) и палитру компонентов (Component Palette).

Окно инспектора объектов, оформлено в виде двухстраничного блокнота (рис.3). Это окно используется для настройки компонента или формы. Первая страница используется для настройки свойств (Properties), вторая – для настройки событий (Events).

Форма является контейнером интерфейсных элементов. Окно форм, (проектировщик форм, Form Designer) используется в процессе разработки интерфейса (рис. 4). Вместе с инспектором объектов проектировщик форм позволяет добавлять компоненты в форму, модифицировать их, связывать обработчики событий с программным кодом на Object Pascal, используя окно редактора кода.

Рис. 4. Окно проектировщика форм.

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

Окно редактора кода (Code Editor, рис.5 справа) позволяет редактировать коды всех модулей (программных единиц), входящих в разрабатываемое приложение. Это окно оформлено в виде многостраничного блокнота. Каждая страница отображает код той или иной программной единицы, входящей в приложение. С помощью проектировщика форм и инспектора объектов представляются все виды частей “фасада” приложения, но без редактора кода нельзя связать эти части в единое целое.

Рис. 5. Окно редактора кода и окно Code Explorer.

По умолчанию слева от редактора кода находится окно Code Explorer (рис. 5). Оно используется для поиска в редакторе кода какого-либо программного элемента: типа, класса, метода и т.д. Это окно можно выделить в самостоятельное и перенести в другое место.

IDE Delphi обладает большой гибкостью в настройке рабочей среды. Для настройки используется диалоговое окно Environment Options, которое выбирается, раскрывая пункты меню ToolsOptions.

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰).

Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим.

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого.

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