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

Сегодня решил немного побаловаться с DataSnap XE2,  разработать небольшую ISAPI-dll и посмотреть как всё это будет работать под управлением моей Windows 7 x64. Надо сказать, что простейший примерчик такого приложения собрался и заработал почти без проблем. Как Вы наверняка знаете, наиболее часто для выполнения операций на сервере используется интерфейс CGI, CGI-скрипты и т.д. Однако компания Microsoft в свое время предложила свой вариант исполнения серверных программ, который называется ISAPI (Internet Server API). В первую очередь ISAPI предназначался для подключения к web-серверу Microsoft под названием Internet Information Server (IIS). Программы ISAPI представляют собой давно известные нам динамически загружаемые библиотеки DLL, которые вызываются Web-сервером, загружаются в память и становятся как бы частью этого Web-сервера, расширяя или изменяя его функциональность. Сейчас для сервера Apache (самого популярного web-сервера) имеется модуль mod_isapi.dll, который позволяет запускать ISAPI-dll. Вообще, если рассуждать о популярности того или иного веб-сервера, то лучше всего начать с посещения вот этого сайта, но мы сегодня не об этом и даже не о том кто круче/быстрее/удобнее IIS или Apache, а о том как написать программку, которая заработает под управлением IIS 7.5 в Windows 7 x64.

Начнем с того, что настроим наш web-сервер IIS.

Установка и настройка IIS в Windows 7

проходит следующим образом: 1. Заходим в «Панель управления -> Программы и компоненты» и выбираем «Включение или отключение компонентов Windows»: 2. В открывшемся окне ищем «Службы IIS» и выбираем следующие необходимые компоненты для установки. Т.к. мне сегодня пришлось достаточно много экспериментировать с IIS, то мой список установленных компонентов оказался таким: 3. Жмем «Ok» и терпеливо ожидаем окончания установки. На этом шаге установка IIS завершена и можно приступать к настройке web-сервера, созданию и тестированию сайта. И здесь может проявиться то самое «почти» без которого я бы мог в начале поста сказать, что «примерчик такого приложения собрался и заработал почти без проблем«. Итак: 4. Заходим в «Панель управления -> Администрирование» и находим там «Диспетчер служб IIS«: Вот здесь и настраивается будущий сайт. По умолчанию, после установки компонентов у Вас на диске C:\\ появится дирректория c:\inetpub\ в которой будут храниться служебные файлы сервера и файлы сайта(-ов), с которыми вы будите работать. При установке в диспетчере уже будет находится один дефолтный сайт, но мы, для порядка создадим свой. 5. В дереве «Подключения» выбираем узел «Сайты», вызываем контекстное меню и выбираем «Добавить веб-сайт…»: 6. В открывшемся окне задаем настройки нашего сайта. На рисунке ниже показаны, которые практически не отличаются от дефолтных (различается только название сайта и его физическое расположение): Теперь в дереве подключений у Вас появился новый сайт «DataSnapSite» который по-идее должен бы запускаться с URL ‘http://localhost’, но, как оказалось, происходит это не всегда: Покопался по Сети в поисках ответа. Оказалось, что у кого-то сайт с такими настройками, как показано выше, работал без проблем, у других — через раз возникали проблемы с ASP.NET у кого-то, как и у меня, сайт вообще не открывался. Может причина в версии IIS, а может и нет, но для себя я нашел два возможных варианта решения этой проблемы: вариант 1: смотрим приложения, которые «слушают» 80-й порт — это могут быть Skype, TeamViewer и другие программки, работающие с сетью. Отключаем эти программы, перезагружаем IIS и снова пробуем зайти на сайт в браузере. вариант 2: если первый вариант не помог, то идем в IIS диспетчере в «Подключения», выбираем наш сайт и меняем ему привязку, на, например, вот такую:   можете также, если необходимо, сменить и порт. После этого сайт должен заработать — можете бросить в корневую директорию сайта файлик index.html и посмотреть на него в браузере: Сайт заработал и на текущем этапе работы нам этого будет достаточно. Мы ещё вернемся к работе с диспетчером IIS и посмотрим, какие ещё возможные проблемы могут возникнуть, а пока идем в Delphi и создаем наше первое приложение ISAPI с DataSnap XE2.

Создаем заготовку ISAPI DLL

Запускаем Delphi и выбираем «File -> New -> Other -> DataSnap Server -> DataSnap WebBroker Application«: В первом шаге помощника выбираем третий пункт — «ISAPI dynamic link library» и жмем Next: На втором и третьем шаге можно оставить все установки по умолчанию. В итоге в менеджере проектов появится новый проект с таким содержанием: ServerMethodsUnit1, как уже понятно из названия будет содержать серверные методы, а модуль WebModule1  содержать компоненты, которые с помощью которых наша ISAPI-dll станет сервером DataSnap и модуль будет выглядеть вот так: Можно сказать, что уже то, что было сделано с использованием помощника — это уже готовая к использованию DLL. Но, пока не будем сильно спешить, а посмотрим на содержимое нашей DLL. Открываем исходный код библиотеки и видим, что наша DLL экспортирует три метода:

exports
  GetExtensionVersion,
  HttpExtensionProc,
  TerminateExtension;

Назначение и описание этих модулей следующее: GetExtensionVersion — предназначена для того, чтобы ISAPI-модуль мог сообщить серверу версию спецификации ISAPI-интерфейса и строку описания ISAPI-модуля. Метод имеет следующее описание:

function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL;

где THSE_VERSION_INFO — это структура:

THSE_VERSION_INFO = HSE_VERSION_INFO;
 
HSE_VERSION_INFO = record
    dwExtensionVersion: DWORD;//версия спецификации
    //описание модуля
    lpszExtensionDesc: array [0..HSE_MAX_EXT_DLL_NAME_LEN-1] of AnsiChar;
  end;

Функция HttpExtensionProc— обеспечивает основную функциональность ISAPI-модуля и используется для обмена данными между модулем и сервером.

function HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD;

Параметр ECB указывает на управляющую структуру. которая выглядит вот так:

 TEXTENSION_CONTROL_BLOCK = record
    cbSize: DWORD;    // size of this struct.
    dwVersion: DWORD; // version info of this spec
    ConnID: HCONN;    // Context number not to be modified!
    dwHttpStatusCode: DWORD;// HTTP Status code
    // null terminated log info specific to this Extension DLL
    lpszLogData: array [0..HSE_LOG_BUFFER_LEN-1] of AnsiChar;
    lpszMethod: PAnsiChar; // REQUEST_METHOD
    lpszQueryString: PAnsiChar; // QUERY_STRING
    lpszPathInfo: PAnsiChar;    // PATH_INFO
    lpszPathTranslated: PAnsiChar;// PATH_TRANSLATED
    cbTotalBytes: DWORD; // Total bytes indicated from client
    cbAvailable: DWORD;  // Available number of bytes
    lpbData: Pointer;    // pointer to cbAvailable bytes
    lpszContentType: PAnsiChar; // Content type of client data
    GetServerVariable: TGetServerVariableProc;
    WriteClient: TWriteClientProc;
    ReadClient: TReadClientProc;
    ServerSupportFunction: TServerSupportFunctionProc;
  end;

Метод TerminateExtension— этот метод отвечает за корректную выгрузку ISAPI-модуля из памяти и освобождение ресурсов.

function TerminateExtension(dwFlags: DWORD): BOOL;

Вот эти три метода и отличают обычную DLL от ISAPI-модуля. Теперь посмотрим, что содержит модуль ServerMethodsUnit1. Как сказано ранее, здесь содержатся серверные методы. Сейчас класс, содержащий эти методы выглядит вот так:

type
{$METHODINFO ON}
  TServerMethods1 = class(TComponent)
  private
    { Private declarations }
  public
    { Public declarations }
    function EchoString(Value: string): string;
    function ReverseString(Value: string): string;
  end;
{$METHODINFO OFF}

Первый метод просто возвращает обратно переданную в параметрах строку, а второй — ту же строку, но перевернутую. Собственно, суть одного из способов оформления серверных методов можно уловить довольно быстро, посмотрев на TServerMethods1. Посмотрим на модуль WebModule1, который был показан на рисунке выше. Этот модуль содержит три компонента: DSServer1 — собственно, сам сервер DataSnap. Необходим для управления серверными методами и передачи данных. DSServerClass1— этот компонент определяет класс с серверными методами, которые могут вызываться клиентским приложением. Должен указывать на DSServer, что и сделано в нашем случае. Для определения класса серверными методами используется событие компонента OnGetClass, обработчик которого в нашем приложении выглядит сейчас вот так:

procedure TWebModule1.DSServerClass1GetClass(
  DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
  PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;

Что из себя представляет TServerMethods1 мы уже видели. DSHTTPWebDispatcher1 — в нашем случае этот компонент обеспечивает выполнение и обработку HTTP-запросов DataSnap сервером. Этот компонент, как и DSServerClass1 должен указывать на DSServer1. С обзором содержимого проекта закончили. Теперь попробуем собрать нашу DLL и запустить её на нашем web-сервере. Сохраняем наш проект, например, в директорию: c:\DataSnap Server\ Так как сегодня мы тренируемся в разработке ISAPI-модулей, то, чтобы впоследствии не «бегать» по длинным путям к готовой библиотеке, в опциях проекта укажем точно такой же путь и к собранному проекту: Теперь собираем по Ctrl+F9 нашу библиотеку, убеждаемся, что она действительно лежит там где надо и снова возвращаемся в Диспетчер IIS.

Запускаем ISAPI-модуль

Сейчас наша DLL лежит в директории c:\DataSnap Server\ и чтобы мы могли её использовать на нашем сайте необходимо выполнить следующие действия в Диспетчере служб IIS: 1. Выбираем в дереве «Подключения» наш сайт, вызываем контекстное меню и выбираем в нем пункт «Добавить виртуальный каталог»: Задаем настройки виртуальной директории как показано на рисунке: Теперь выбираем виртуальную директорию в «Подключениях» и заходим в настройку «Подключаемых модулей»: Теперь выбираем «Просмотр каталога» и убеждаемся, что просмотр включен: На текущий момент обработчик файлов *.dll (ISAPI-dll) должен быть отключен. Чтобы его включить выбираем запись в списке, жмем «Изменение разрешения функции» и ставим флажок «Выполнение»: Следующий шаг — разрешить запуск неуказанных модулей ISAPI. Для этого в дереве подключений выбираем самый верхний узел и ищем опцию «Ограничения ISAPI и CGI«: Здесь выбираем опцию «Изменить параметры..» и в открывшемся окне ставим флажок «Разрешить выполнение неуказанных модулей ISAPI»: И последний шаг настройки на котором снова вылезло то самое «почти без проблем». Для того, чтобы мы могли запускать под Windows x64 и 32-битные ISAPI-модули необходимо: Выбрать в подключениях «Пулы приложений», найти в списке пул, относящийся к нашему сайту и открыть окно с дополнительными опциям: Вот теперь, если Вы сделали все, что было сказано выше, наш ISAPI-модуль должен заработать. Проверим. Выбираем в подключениях виртуальную директорию «test» и в правом столбце («Действия») жмем опцию «Обзор». В браузере должна открыться страничка с перечнем всех файлов и директорий каталога. У меня она выглядит вот так: Выбираем в списке нашу DLL (у меня это Project15.dll) и видим следующую надпись в браузере: Это ни что иное как результат работы одного из методов в нашем проекте:

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content := 'DataSnap Server';
end;

DLL заработала, но это ещё не все. Как быть с нашими серверными методами? Для того, чтобы мы могли воспользоваться серверными методами подключимся к DataSnap-серверу и напишем небольшое клиентское приложение, которое будет использовать методы EchoString и ReverseString.

Подключаемся к DataSnap-серверу и пишем клиентское приложение

Для создания нового подключения выбираем в менеджере проектов Delphi вкладку Data Explorer, ищем в дереве «DataSnap», вызываем контекстное меню узла и выбираем опцию «Add New Connection»: Задаем название нового подключения: Выбираем в Data Explorer наше новое подключение и в контекстном меню «Modify Connection«. Здесь мы должны задать настройки соединения, соответствующие тем, которые мы задавали в Диспетчере IIS: Проверяем соединение, нажав «Test Connection» — все должно работать замечательно: Теперь можете убедиться, что в Data Explorer в списке процедур появились наши серверные методы: Теперь мы можем протестировать работу EchoString и ReverseString, не создавая клиентского приложения. Для этого дважды кликаем по необходимому методу и в открывшемся окне задаем значение параметра Value: Жмем кнопку «Execute» в верхней части окна и убеждаемся, что метод вернул нам ответ: Раз соединение работает корректно — самое время написать небольшое клиентское приложение. Создаем новый проект и бросаем на форму компоненты как показано на рисунке: Теперь открываем вкладку «dbExpress» палитры компонентов Delphi, бросаем на форму компонент TSQLConnection и устанавливаем ему значение свойства «ConnectionName = FirstDataSnapConnection». В результате в Object Inspector’e Вы увидите следующие значения свойств Driver: Можете также переключить свойство Connected в значение True. Теперь создадим клиентский модуль для вызова серверных методов. Для этого снова выбираем TSQLConnection и в Object Inspector’е жмем опцию «Generate DataSnap client classes»: В итоге создастся новый модуль, который будет содержать следующий класс:

type
  TServerMethods1Client = class(TDSAdminClient)
  private
    FEchoStringCommand: TDBXCommand;
    FReverseStringCommand: TDBXCommand;
  public
    constructor Create(ADBXConnection: TDBXConnection); overload;
    constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload;
    destructor Destroy; override;
    function EchoString(Value: string): string;
    function ReverseString(Value: string): string;
  end;

Подключаем этот модуль в uses нашего главного модуля приложения и пишем такой обработчик OnClick кнопки:

uses Unit1;
 
{$R *.dfm}
 
procedure TForm17.Button1Click(Sender: TObject);
var Server: TServerMethods1Client;
begin
  Server:= TServerMethods1Client.Create(SQLConnection1.DBXConnection);
  try
    label3.Caption:=Server.EchoString(Edit1.Text);
    label5.Caption:=Server.ReverseString(Edit1.Text);
  finally
    Server.Free;
  end;
end;

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

Как видите, в нашем примере все прекрасно работает. Остается только добавить то, что на этапе работы с IIS мы могли бы обойтись и без включения поддержки запуска 32-битных ISAPI-модулей, т.к. Delphi XE2 может без проблем мобрать 64-битную библиотеку. На всякий случай я проверил этот тестовый пример — скомпилировал проект ISAPI-модуля для платформы win64 и отключил для пула приложений в IIS запуск 32-битных модулей — работоспособность клиента при этом никак не нарушилась.

На сегодня картинок хватит :) Всем удачи и до новых встреч.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
10 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
teran
23/08/2012 21:19

какой острый сюжет 8)
а из браузера как методы длл вызывать далее?

Arvi
Arvi
28/08/2012 19:30

test connection не прошел. сказал «borland.data.tdbxerror 405 method not allowed». до этого все работало.
подскажешь?

Arvi
Arvi
29/08/2012 01:22

DSHTTPWebDispatcher.WebDispatch.MethodType = mtAny
такая беда случилась и на домашнем компе

Arvi
Arvi
29/08/2012 17:34

заработало
дело было в IIS
у меня в компонентах винды «службы ISS» были включены все. сделал как у тебя и заработало.
будем посмотреть.
спасибо.

Zelenyy Sharik
06/03/2013 00:49

Здравствуйте. Делаю все как у вас, жму тест коннектион , а он ругается Borland.Data.TdbxError: Communication filter RSA is not registered. Filter class needs to be registered in order to communicate with the server.

pivbul
24/08/2015 03:02

А случайно не знаете случайно, как в DLL-ISAPI реализовать вызов функции из другой (обычной) DLL? обычный метод stdcall;external ‘xxx.dll’; вешает ISAPI…