Режим IntraWeb Page-mode.
Николай
Ренжиглов ®
IntraWeb поддерживает два режима разработки сайтов: Application (Stand Alone application) и Page-Mode (речь идет, как и ранее, о поставке продукта вместе с Delphi 7.0 Enterprise и Architect). Описанный ранее Stand Alone-режим реализовывался как отдельный сервер или служба Windows 2000. Для сравнительного анализа с режимом Page-mode, который мы рассмотрим в этой главе, уделим внимание режиму IntraWeb-приложения, расширяющего функции другого (здесь и далее “основного” сервера) IIS или Apach.
Когда приложение разрабатывается как расширение основного сервера, все запросы направляются на обработку этим сервером, установленным на компьютере. Основной сервер перенаправляет запросы IntraWeb-приложению, которое генерирует ответ. Ответ передается основному серверу и далее клиенту для просмотра в браузере:
|
HTTP-клиент |
|
WEB-сервер |
|
IntraWeb- приложение |
|
|
|
|
|
|
Справа на рисунке показан модуль расширения основного сервера, работающий в отдельном потоке. Для сравнения изобразим те же объекты в случае работы Stand alone-приложения:
|
HTTP-клиент |
|
IntraWeb- приложение |
|
|
|
|
В этой ситуации каждый серверный поток стартует при вызове нового экземпляра WEB-браузера на клиентском компьютере. Сколько окон браузера с клиентской стороны, столько и потоков на сервере.
Режим Page-mode
используется для создания страниц, работающих в составе многостраничного WEB-сайта. Здесь IntraWeb-приложение также
работает через ISAPI-расширение основного сервера, но “несет ответственность” только за
свою страницу сайта. Функциональности таких страниц могут быть также
реализованы с использованием других языков (PHP или ASP для IIS), а
серверные расширения как приложения Kylix, Delphi или C++ Builder.
В режиме Page Mode запрос клиента также обрабатывается основным сервером компьютера, который передает его дальше ISAPI-расширению, написанному, например, с использованием WebBroker или WebSnap. Далее диспетчер страниц WebBroker направляет его IntraWeb-приложению, генерирующему ответ с использованием стандартного механизма WebSnap. Но в этот механизм также включается IWPageProducer, возвращающий страницу как IWPageForm, а также такой элемент как IWModuelController. Вот как это выглядит на схеме:
|
HTTP-клиент |
WEB-сервер |
WebSnap- расширение |
IntraWeb Page Mode- приложение |
|
|
|
|
|
IntraWeb-часть такого приложения не порождает отдельного потока и работает в потоках, порожденных WebBroker или WebSnap-кодом. В этом радикальное отличие модели от Stand Alone Application, в которой каждый поток связан с конкретной пользовательской сессией или, иначе говоря, с окном браузера. Поговорим об этом подробнее.
Отличие от режима Application.
В режиме Stand Alone Application запрос браузера порождает сессию в отдельном потоке, который создан и существует, пока данная сессия активна. Методы завершения сессии описывались ранее – это истечение времени time out или выполнение метода Terminate для объекта Application. Все это сильно напоминает работу в среде клиент-сервер, когда для каждого пользователя создается отдельный экземпляр клиентского приложения и отдельное подключение к базе данных, сохраняемое в течение всей сессии.
Работа в среде WEB вообще строится немного иначе. Поток, порожденный текущим запросом, после обработки модулем ISAPI удаляется из памяти сервера. Поддержка состояния на клиентской стороне требует в этом случае отдельного программирования или использования уже готовых программных структур, как в случае совместного использования IntraWeb и WebSnap.
Выбор между режимами Application и Page Mode.
Вопрос о том, какой подход использовать для создания IntraWeb-проекта, Application или Page Mode, в основном решает метод обработки пользовательской сессии. Там, где требуется полное управление пользовательской сессией и слежение за состоянием бизнес-объекта в процессе работы, форма Application mode предпочтительна.
С другой стороны, работа WEB-сайта с независимыми страницами ("Новости", "Форум", "Консультации" и так далее) не требует контроля сессии в полном объеме. Пользователь посетил один раздел, перешел к другому, третьему, но при такой структуре сайта нет необходимости следить за этими переходами. Для разработки сайтов такого рода более подходит Page Mode - модель.
Область совместного применения IntraWeb и WebSnap.
IntraWeb позволяет реализовать большую интерактивность, выделив страницы, реализующие диалог с пользователем, в Page-mode-приложения. Режим Page-mode очень хорошо интегрируется в приложения, написанные с использованием технологии WebSnap, появившейся в версии Delphi 6.0. Эта технология, прежде всего, направлена на автоматизацию стандартных процессов, происходящих при работе WEB-сайта:
· Login Services. Загрузка пользователя производится специальным объектом загрузки. Этот объект регистрирует пользователя в соответствии с установленной моделью безопасности и следит за сроками действия разрешений на доступ к страницам.
· User Management Services. Система поддерживает список пользователей со всей необходимой информацией о них (данных загрузки, предпочтениях и так далее).
· File Uploading Services. Это объект, автоматизирующий довольно сложный для программирования процесс загрузки файлов на сервер.
· Access Rights. Объект производит контроль за правами доступа как стандартными средствами, установленными в Windows, так и разработанными специально.
·
File
Management Services. Этот объект облегчает просмотр
содержимого произвольного файла, хранящегося на сервере. Автоматизирует процесс
контроля логических путей на сайте и физических на диске.
· Server-side Scripting. Поддерживаются скрипты JavaScript, VBScript или другие ActiveScrip-языки. Скрипты на серверной стороне являются связующим звеном между скомпилированным Delphi-кодом и логикой, имеющейся на странице сайта.
Прежде, чем мы изучим пример использования WebSnap совместно с IntraWeb, давайте вкратце рассмотрим технологии программирования для WEB и их эволюцию в Delphi.
1. История вопроса.
Возможность динамического формирования ответа сервера была впервые реализована с использованием CGI. Однако повышение интерактивности сайтов в этих рамках давалось ценой все возрастающих усилий не только программистов, WEB-дизайнеров и инженеров, но и администраторов баз данных и COM/CORBA-разработчиков. Фирма Borland участвовала в создании средств интерактивной WEB-разработки самым активным образом. Причем основные усилия были направлены на создание оптимальной архитектуры для систем разработки. Основными технологиями разработки WEB-приложений под Delphi на сегодняшний день являются
·
WEB
broker
·
WEB
Snap
·
WEB
Services
Технология WEB Broker была первой попыткой фирмы Borland (Delphi 4.0) представить инструментарий для разработки WEB-приложений. Модули, созданные в рамках WEB-Broker, работали либо как CGI-приложения, либо как ISAPI-расширения стандартных WEB-серверов. Эффективность программирования была на уровне языков PHP, а о RAD-разработке не шло речи вообще – эта технология была и остается полностью не визуальной. Но развитие Delphi продолжалось и в версии 6.0 появилась технология WEB Snap. WebSnap максимально эффективна для работы с IntraWEB, поскольку эта технология способна поддерживать несколько разрабатываемых WEB-модулей, вызывать методы и свойства принадлежащих им объектам посредством скриптов, отделять WEB-дизайн, сохраненный в CSS и HTML-файлах от кода, хранящегося в серверных DLL-библиотеках. В DataSnap методы обработки бизнес-кода проекта и методы поддержки архитектуры WEB-сервера разделены. Это разделение достигается при помощи WEB-модулей следующих типов:
· WebDataModule - аналог модуля данных в Delphi. Хранит невизуальные компоненты, доступные всем формам проекта. Содержимое модуля не отображается в режиме run-time.
· WebPageModule – модуль, содержащий компоненты для отображения одной HTML-страницы сайта. Является контейнером для этих компонентов, поскольку вид страницы определяется HTML-шаблоном, хранящемся в файле с аналогичным расширением.
WEB Services, службы WEB, позволяют приложениям экспонировать некоторые интерфейсы (данные и функции) для других приложений, работающих в сети и использующих WEB-сервера для различных платформ. Обмен данными между приложениями использует платформо-независимый протокол SOAP.
Итак, WEB Snap – это попытка предложить разработчикам автоматизацию
процесса создания WEB-сайтов,
прежде всего решающих типовые задачи. Прежде чем анализировать работу WebSnap+IntraWeb проектов, рассмотрим вопрос об организации
отладки серверных DLL-расширений.
2. Способы отладки ISAPI DLL-расширений сервера IIS.
Отладка ISAPI DLL-приложений перестала быть тем
кошмаром, которым она была еще недавно в ранних версиях Delphi, когда,
например, одной из рекомендаций был перезапуск WEB-сервера для каждой
отладочной сессии. В Delphi 6 Professional и Enterprise появился встроенный
отладчик Web App Debugger, работающий как COM-сервер. Кроме использования этого средства мы еще подробно
рассмотрим отладочные компоненты Windows NT/2000,
зарегистрированные в службах этой ОС.
2.1. Web App Debugger.
Программа Web App Debugger доступна в IDE Delphi в позиции меню Tools и работает как WEB сервер с использованием порта 1024 по умолчанию. Передача запроса отлаживаемому приложению построена на COM-технологии. Программа собирает статистическую информацию по запросам и обеспечивает отображение справок по ним.
Как только отработает мастер по созданию WEB-приложения (путь File|New|Other|WebSnap|Application),

Delphi создаст пустую форму, содержащую в себе код регистрации OLE-сервера и его GUID. Эту информацию включает в себя отладчик, предоставляя OLE-сервер для выбора в процессе отладки. Подробнее об этом процессе можно прочесть, например, в документации по Delphi и других источниках [1]. Для отладки таким способом уже имеющегося приложения (что мы и будем делать в дальнейшем c примерами IntraWeb) нужно создать программу именно такого типа, какой мы собираемся отлаживать. Затем удалить WEB-модуль, добавить вместо него имеющийся, добавить строку настройки свойства WEBModuleClass объекта WEBRequestHandler и сделать еще много чего. Это неудобно, но зато не требует установки и запуска IIS!
Продолжим. В проекте установим точку останова в каком-либо модуле и запустим приложение Tools|Web App Debugger. Появится окно сервера с кнопкой Start. Нажмем эту кнопку и перейдем по ставшей активной ссылке на сервер:

Выберем из списка нужный COM-сервер
с именем MyApp1 и
нажмем кнопку Go. Запустится WEB-браузер и сработают
возможно установленные в программе точки останова.

Процесс отладки с помощью Web App Debugger
начался. Этот путь достаточно прост
и эффективен, но в случаях, когда использование сервера IIS необходимо, например, для оценки реальной
работы сайта, существует еще один метод.
2.2. Отладка при помощи компонентов, зарегистрированных в службах.
Этот вид отладки требует работы на вашей машине IIS версии не ниже 5.0. Он также достаточно прост и эффективен для Delphi-приложений и также использует технологию COM. На вашем компьютере должна функционировать MS Windows 2000 Professional или Server и MS Distributed Transaction Coordinator. Перейдем в список сервисов (Administrative tools|Services) и активизируем MS DTC:

Если старт MS DTC закончится неудачей, проинициализируйте log-файл для этой системы
Run>Msdtc -resetlog
и повторите процедуру старта.
Теперь
создадим виртуальную директорию IIS, например, с именем IWGuess, ссылающуюся на физический путь, по которому расположен пример GuessWB или любой другой из представленных в
разделе /Demos/IntraWeb (Administrative tools|Personal Web Manager|Add Virtual Directory, не забудьте включить "галочку" Execute для директории):

Вызовем свойства (Administrative tools|Internet Services Manager|Default Web Site) этой директории и установим параметры как показано на скриншоте:

Обратите внимание, что свойство Application Protection равно значению Isolated. Это означает, что приложение GuessWB.DLL будет выполняться под управлением вновь созданного COM+ приложения в отдельном процессе. Кроме параметра Application Protection в этом окне изменено свойство Local Path и Application Name. Значение "GuessWB.dll" в позиции Application Name не имеет к исполняемому модулю никакого отношения и носит мнемонический характер. Можно вообще оставить это поле пустым.
COM+
приложения могут рассматриваться как компоненты, включающие в себя код
авторизации, поддержку транзакций и многое другое. Это более широкий взгляд на
то, что мы делаем сейчас, но тем не менее, воспользуемся технологией работы Windows с компонентами COM+ и рассмотрим свойства нашего компонента, как
показано ниже:

Выберем позицию меню Properties и на закладке Identity установим Interactive User - the current logged on user, чтоб не вводить в процессе отладки никаких паролей.
Кроме того, с закладки General возьмем GUID для COM+ приложения (например, в ClippBoard) для последующего использования в среде Delphi.

Перейдем в Delphi IDE, загрузим проект GuessWB. В командной строке запуска установим:
Dllhost.exe - это Windows-приложение, в адресном пространстве которого выполняется COM+ или создается его контекст. Идентификатор COM+ компонента указан в строке Parameters.
Установим точку останова, например, при нажатии кнопки butnGuess, запустим приложение и отдельно окно WEB-браузера с URL http://100.100.100.100/iwguess/guesswb.dll/guess (здесь указан тестовый IP-адрес). При нажатии на кнопку, в среде Delphi IDE происходит остановка:

Если в момент остановки вам доступно окно Component Services, обратите внимание на анимацию соответствующей пиктограммы: шарик вращается - значит COM-приложение работает. Завершить проект можно, например, нажав Ctrl+F2, а останавливать COM-приложение (что не всегда одно и то же) - путем выбора позиции ShutDown в меню компонента при включенной анимации.
3. Пример WebSnapServey.
После того, как мы решили проблемы, связанные с
отладкой ISAPI DLL, перейдем к основной цели главы - рассмотрению примера
IntraWeb Page Mode - приложения. В
поставке Delphi имеется
пример WebSnapServey (…Delphi7\), позволяеющий разобраться в следующем:
Зарегистрируйте COM+ компонент для отладки примера, как описано выше, и запустите его на выполнение. Почти весь проект состоит из взаимодействия компонентов WebSnap и Web-форм, подробное объяснение методов работы с которыми выходит за рамки данной главы. Если читатель недостаточно знаком с платформой WebSnap, отсылаем его к документации по Delphi и другим многочисленным источникам.[2]
Подробно проанализируем работу проекта.
Добавленный в проект TIWModuleController включается в механизм обработки запросов WebSnap. Этот компонент напрямую наследуется от TComponent и экспонирует интерфейс IWebDispatch. Для обеспечения работы TIWModuleController в проект включен также и TWebDispatcher, располагающийся на закладке Internet палитры компонентов.
На этапе разработки демонстрационного примера авторами в проект были добавлены WebSnap Page-модули:

Обратите внимание, что затем компоненты TPageProducer удалены и заменены на TIWPageProducer (с закладки IntraWeb). Вот результат:

Этот IW-продюсер будет "продуцировать" в примере IntraWeb-форму, которая создается в проекте с использование закладки IntraWeb: File| New| Other| IntraWeb| Page Form. Продюсер IW-формы обрабатывает только одно событие OnGetForm. Определим обработчик события так, чтобы продюсер "знал" с какой IW-формой он будет работать:
procedureTPage1.IWPageProducer1GetForm(ASender: TIWPageProducer;
AWebApplication: TIWApplication; var VForm: TIWPageForm);begin
VForm:=TformMain.Create(AWebApplication)end;
При
появлении ошибки трансляции, связанной с этим кодом, проверьте наличие
объявлений модулей IWApplication и IWPageForm в строке uses.
Запустим проект на выполнение (пароль и логин для
загрузки страниц проекта один и тот же: test). В момент обработки события продюсера создается
один экземпляр IW-формы для
каждой WEB-страницы, как это
и принято в WebSnap. При
голосовании на странице formPage1 пользователь нажимает кнопку Vote. Начинается обработка события OnClick и приложение производит анализ введенной
информации. Поскольку работа этой
части кода имеет принципиальное значение, приводим полностью соответствующий
фрагмент.
procedure TformPage1.butnVoteClick(Sender: TObject);
var
LBest:
TSTMovie;
LWorst:
TSTMovie;
begin
LBest :=
miMotionPicture;
LWorst :=
miMotionPicture;
if cmboBest.ItemIndex = -1 then
begin
textMsg.Lines.Text := 'Please select a choice for best Star Trek
movie.';
end else
if cmboWorst.ItemIndex = -1 then begin
textMsg.Lines.Text := 'Please select a choice for worst Star Trek
movie.';
end else
begin
LBest :=
TSTMovie(cmboBest.Items.Objects[cmboBest.ItemIndex]);
LWorst :=
TSTMovie(cmboWorst.Items.Objects[cmboWorst.ItemIndex]);
if
LBest = LWorst then begin
textMsg.Lines.Text := 'Sorry - but you cannot pick the same movie for
best and worst.';
end
else begin
if
WebContext.Session.Values['Confirm'] <> 'Y' then begin
if
LBest = miFinalFrontier then begin
textMsg.Lines.Text := 'Ugh. The Final Frontier was trully horrid. Are
you sure that is'
+
' your choice for best?';
butnVote.Caption := 'Vote with my questionable choice anwyays';
WebContext.Session.Values['Confirm'] := 'Y';
end
else if LBest = miVoyageHome then begin
textMsg.Lines.Text
:= 'Good choice! The Voyage home was good wasn''t it?';
butnVote.Caption
:= 'Record my vote!';
WebContext.Session.Values['Confirm']
:= 'Y';
end;
end;
end;
end;
textMsg.Visible := textMsg.Lines.Count > 0;
if not
textMsg.Visible then
begin
RecordVote(LBest, LWorst);
ProduceResponse := False;
DispatchPageName('PageResults', WebContext.Response, []);
end;
end;
Строки в конце обработчика выделены
для упрощения ссылок на них. Если в процессе голосования возникают какие-либо
замечания к заполнению полей, отображается
элемент формы textMsg, содержащий текст замечания. В этом случае
выделенные строки не выполняются. Форма передается клиенту как ответ сервера и
мы видим её же в окне браузера. Это происходит потому, что:
1. свойство IWPageForm-формы ProduceResponse=TRUE (по умолчанию) и форма передается;
2. свойство формы PostToSelf=TRUE - данные отправляются в качестве ответа самой же
форме. Заметьте, что свойство формы AutoProcess установлено в TRUE (это значение по умолчанию), что позволяет
автоматически обрабатывать значения HTTP-элементов формы, а также их состояние.
При
отключенном параметре AutoProcess=FALSE жать на кнопку Vote бесполезно - событие
formPage1.butnVoteClick(Sender) даже не будет вырабатываться. В этом случае submit-компонент (кнопка) формы не будет
автоматически обнаруживаться. А вот для формы formResults, на которой
отображаются результаты голосования в виде чарта, это свойство должно быть
отключено (AutoProcess=FALSE), ведь там
нет submit-компонентов
и она должна быть передана диспетчеру страниц без их анализа.
Если же голосование проведено без замечаний, помеченный код выполняется. При этом:
1. происходит вызов процедуры RecordVote, в которой результаты голосования
заносятся в списки. Процесс протекает под защитой критических секций и причину
использования этого метода работы с потоками мы обсудим ниже.
2. Значению ProduceResponse присваивается значение FALSE, запрещающее передачу формы в качестве
ответа сервера.
3. Вызывается процедура DispatchPageName,
которая, используя интерфейс IPageDispatcher, указывает диспетчеру страниц проекта, что нужно в качестве
ответа WebSnap-приложения WebContest.Response использовать страницу с именем "PageResults". Далее этот ответ будет передан WEB-серверу, который отошлет её клиенту.
Клиент увидит в окне браузера чарт с результатами голосования.
Такова схема работы проекта. Возникает вопрос:
почему результаты голосования записываются с применением потокозащищенного
кода, а, например, при рисовании на полотне (canvas) формы formResults нет даже намека на потоки.
Дело в том, что списки GVotesBest
и GVotesWorst модуля Globals являются глобальными, доступ к которым
осуществляется из разных "клиентских " запросов (сессий). Это требует
защиты, реализованной в проекте в виде критических секций.
Процедура formResults.IWPageFormRender,
рисующая на полотне, вызывается при выполнении DispatchPageName (последний оператор в выделенном фрагменте)
и работает в рамках текущей пользовательской сессии WebContext.Session. В
рамках данной пользовательской сессии определено и значение параметра Confirm,
хранящего признак того, были ли высказаны пользователю комментарии относительно
его выбора. Значения этому параметру
также присваиваются простым оператором без использования потоков:
WebContext.Session.Values['Confirm'] := 'Y';
[1] М. Канту. Delphi 6.0 для профессионалов. Изд. Дом Питер 2002
[2] М. Канту. Delphi 6.0 для профессионалов. Изд. Дом Питер 2002