При разработке веб-приложений на Delphi, в частности, с использованием ISAPI-приложений, может возникнуть проблема с подключением к базе данных через компонент ADO. В данной статье мы рассмотрим, почему может возникать ошибка при попытке подключения в глобальном контексте ISAPI-приложения, и как можно решить эту проблему.
Описание проблемы
При попытке инициализации соединения с базой данных в секции инициализации приложения, использующего TISAPIApplication, возникает ошибка. Пример кода, использующего TADOConnection, не может быть выполнен на этапе инициализации приложения, что приводит к зависанию приложения без выдачи исключения.
library ISAPIBareBones;
uses
ActiveX,
ADODB,
// ... другие используемые модули
var
conn: TADOConnection;
begin
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
CoInitialize(nil);
conn := TADOConnection.Create(nil);
conn.ConnectionString := 'Provider=SQLOLEDB.1;xxx';
try
conn.Open;
except
on E: Exception do
LogException(E);
end;
// ... продолжение кода
end.
Следует отметить, что аналогичный код в обработчике конкретного запроса (Delphi webAction) работает корректно. Предполагается, что проблема может быть связана с правами выполнения в IIS на уровне ISAPI-приложения.
Контекст проблемы
Приложение, разработанное в Delphi XE SPI, запускается на Windows 7 64-bit, IIS 7.5 и Windows Server 2008 R2. Проблема возникает с использованием как MS-SQLServer OLEDB, так и Sybase ASE провайдера. При вызове метода conn.Open соединение не устанавливается, и ISAPI-приложение зависает.
Поиск решения
Для решения проблемы необходимо учесть ограничения, накладываемые на инициализацию DLL. В частности, в инициализирующем коде не следует вызывать функции COM, включая создание объектов ADO.
Подтвержденный ответ
Согласно рекомендациям MSDN, инициализация ISAPI-приложения должна быть выполнена в функции GetExtensionVersion. Это функция предназначена не только для отображения версии ISAPI, но и для выполнения всех необходимых действий по инициализации, включая создание соединений с базой данных.
Альтернативный ответ
В качестве альтернативы можно было бы предположить, что после вызова Application.Run и инициализации приложения можно безопасно выполнять операции с ADO. Однако, это может быть опасным, так как Application.Run вызывается из DLLMain, и, следовательно, все еще находится в небезопасном контексте.
Решение проблемы
Используйте функцию GetExtensionVersion для инициализации соединения с базой данных. В этом контексте можно безопасно создать соединение, не нарушая ограничений, накладываемых на инициализацию DLL.
library Project1;
uses
// ... используемые модули
function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL; stdcall;
begin
Result := Web.Win.ISAPIApp.GetExtensionVersion(Ver);
// Создание соединения с базой данных здесь
end;
exports
GetExtensionVersion,
HttpExtensionProc,
TerminateExtension;
begin
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
Application.WebModuleClass := WebModuleClass;
Application.Run;
end.
Заключение
При разработке ISAPI-приложений на Delphi важно понимать ограничения, связанные с инициализацией DLL и работой с COM-объектами. Использование функции GetExtensionVersion для инициализации соединения с базой данных является безопасным и рекомендуемым способом решения описанной проблемы.
При разработке ISAPI-приложения в Delphi XE SPI возникла проблема с соединением с ADO из-за ограничений, связанных с инициализацией DLL и работой с COM-объектами в контексте прав IIS, что требует перемещения инициализации базы данных в функцию
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS