-
Добрый день. Пишу клиент-вебсерверное приложение (SOAP). В серверной части в WebModule (Unit1.pas) добавил компоненты FibPlus: TpFIBDatabase, TpFIBTransaction, TpFIBDataSet. Настроил подключение к своей базе данных и хочу просто передать какое-нибудь значение из базы в клиентскую часть (потом хочу передавать весь датасет, но это потом). Написал функцию для обращения к таблице из базы (S1Impl.pas) ... function Ts1.GetDataFromBase(s:AnsiString): AnsiString; stdcall; begin Log('Начало функции'); // ведем лог в файл try WM.FbDatabase.Connected:=true; // здесь выдает Access Violation WM.FbFirms.Active:=true; Result:=WM.FbFirmsFIRMA.AsString; WM.FbDatabase.Connected:=false; except on E: Exception do Log('Произошла ошибка '+E.Message); //, E.HelpContext end; Log('Конец функции'); end; WM - это TWM = class(TWebModule) FbDatabase: TpFIBDatabase; FbFirms: TpFIBDataSet; При вызове функции из клиентского приложения я получаю "Access violation at address 0055F78F in module 'webserv1.exe'. Read of address 000000AC" на строке WM.FbDatabase.Connected:=true; Если не обращаться к базе данных, то все нормально - никаких ошибок. После долгих экспериментов увидел, что "Ахсекс виалейшн" вываливается при любом обращении к любому свойству/методу FbDatabase. Похоже что на момент обращения не создан сам WebModule (WM). Как это проверить? PS. Использую BDS2006, FibPlus, Firebird2.0.1, сервер Apache Ссылка на исходники: http://www.onlinedisk.ru/file/405488/ (клиентская часть) http://www.onlinedisk.ru/file/405493/ (серверная часть)
-
зачем это проверять, это и так из контекста ясно что не создан.
-
Это проверять не надо, а надо делать так чтобы не проверять
-
Медвежонок Пятачок, Anatoly Podgoretsky Ткните носом пожалуйста что и где прописать? У меня же прописано создание WM program WebServ1;
uses
WebBroker,
CGIApp,
Unit1 in 'Unit1.pas' ,
S1Intf in 'S1Intf.pas',
S1Impl in 'S1Impl.pas';
begin
Application.Initialize;
Application.CreateForm(TWM, WM); Application.Run;
end.
-
Note
The Web module that you set up at design time is actually a template. In ISAPI and NSAPI applications, each request message spawns a separate thread, and separate instances of the Web module and its contents are created dynamically for each thread.
Иными словами при поступлении запроса используется не тот модуль, на который указывает проинициализированная переменная, а другой.
Application.CreateForm(TWM, WM); // разьве этого недостаточно?
-
Вроде бы как бы достаточно, если только Ts1 не вызывается до создания WM или где нибудь WM не разрушается. И конечно все компоненты участвующие в процессе также созданы. А сообщение "Read of address 000000AC" говорит, что это не так. Дело к тому же может быть в обработчиках, может там что либо не в порядке, а не WM Сообственно ты код почти не показываешь.
-
> Медвежонок Пятачок © (13.04.10 15:49) [4]
Это к вопросу не относится, вот когда он будет делать isapi вот тогда будет по делу. А вот загадочный TS1 это интереснее, но информации о нем нет.
-
Показать код не проблема. Вот для серверной части проекта. Код для S1Impl.pasunit S1Impl;
interface
uses InvokeRegistry, Types, XSBuiltIns, S1Intf, Unit1, Classes, SysUtils, FIBDatabase, pFIBDatabase, DB, FIBDataSet, pFIBDataSet, Unit2;
type
TS1 = class(TInvokableClass, IS1)
public
LogLst: TStringList;
function GetTT(d:integer): TArrString; stdcall;
function GiveX2(d:integer): integer; stdcall;
function GetDataFromBase(s:AnsiString): AnsiString; stdcall;
procedure Log(str:AnsiString); stdcall;
end;
implementation
function Ts1.GetTT(d:integer): TArrString; stdcall;
var A1: TArrString;
begin
SetLength(A1,2); A1[0] := 'val1'; A1[1] :='val2';
end;
function Ts1.GiveX2(d:integer): integer; stdcall;
begin
Log('вызываю GiveX2');
Result:=d*2;
end;
function Ts1.GetDataFromBase(s:AnsiString): AnsiString; stdcall;
begin
Log('Начало функции');
try
WM.FbDatabase.Connected:=true; wM.FbFirms.Active:=true;
Result:=WM.FbFirmsFIRMA.AsString;
WM.FbDatabase.Connected:=false;
except
on E: Exception do Log('Произошла ошибка '+E.Message);
end;
Log('Конец функции');
end;
procedure Ts1.Log(str:AnsiString); stdcall;
begin
LogLst:=TStringList.Create;
if (FileExists('WLog.txt')) then LogLst.LoadFromFile('WLog.txt');
LogLst.Add(str);
LogLst.SaveToFile('WLog.txt');
end;
initialization
InvRegistry.RegisterInvokableClass(TS1);
end. Код для S1Intf.pasunit S1Intf;
interface
uses InvokeRegistry, Types, XSBuiltIns, Unit1;
type
TArrString = array of string;
IS1 = interface(IInvokable)
['']
function GetTT(d:integer): TArrString; stdcall;
function GiveX2(d:integer): integer; stdcall;
function GetDataFromBase(s:AnsiString): AnsiString; stdcall;
end;
implementation
initialization
InvRegistry.RegisterInterface(TypeInfo(IS1));
end. Код для Unit1unit Unit1;
interface
uses
SysUtils, Classes, HTTPApp, InvokeRegistry, WSDLIntf, TypInfo,
WebServExp, WSDLBind, XMLSchema, WSDLPub, SOAPPasInv, SOAPHTTPPasInv,
SOAPHTTPDisp, WebBrokerSOAP, FIBDatabase, pFIBDatabase, DB, FIBDataSet,
pFIBDataSet;
type
TWM = class(TWebModule)
HTTPSoapDispatcher1: THTTPSoapDispatcher;
HTTPSoapPascalInvoker1: THTTPSoapPascalInvoker;
WSDLHTMLPublish1: TWSDLHTMLPublish;
FbDatabase: TpFIBDatabase;
FbTransRead: TpFIBTransaction;
FbTransWrite: TpFIBTransaction;
FbFirms: TpFIBDataSet;
FbFirmsFIRMA: TFIBStringField;
FbFirmsFIRMKOD: TFIBSmallIntField;
FbFirmsFIRMNAME: TFIBStringField;
FbFirmsFIRMPASS: TFIBStringField;
procedure WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
procedure WebModuleCreate(Sender: TObject);
procedure WebModuleDestroy(Sender: TObject);
private
public
end;
var
WM: TWM;
implementation
procedure TWM.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
WSDLHTMLPublish1.ServiceInfo(Sender, Request, Response, Handled);
end;
procedure TWM.WebModuleCreate(Sender: TObject);
begin
FbDatabase.Connected:=true;
FbFirms.Active:=true;
end;
procedure TWM.WebModuleDestroy(Sender: TObject);
begin
if (FbDatabase.Connected) then
begin
if (FbTransRead.InTransaction) then FbTransRead.Rollback();
if (FbTransWrite.InTransaction) then FbTransWrite.Rollback();
FbDatabase.CloseDataSets();
FbDatabase.Close();
end;
end;
end. Для клиентской части код нужен? PS. Не стесняйтесь обзывать меня балбесом, но только помогите понять как писать вебсерверы с БД :)
-
Разве TS1 можно не создавать?
-
> Разве TS1 можно не создавать?
Anatoly Podgoretsky, не знаю даже что ответить... Этот код генерирует сам BDS, если выбрать File -> New -> Other... -> WebServices -> SOAP Server Application (я лишь пытаюсь прикрутить подключение к БД).
Если нужно создавать TS1, то где и как?
Хочу заметить, что функция GiveX2 нормально вызывается из клиентского приложения и возвращает то что надо (исходное число умноженное на 2).
-
> Rusland © (13.04.10 16:49) [7]
А теперь переноси всё своё барахло из WebModule в реализацию своего интерфейса TS1. Ибо, делфи создаёт наследника WebModule не для того, что бы туда не думая всякий мусор пихали.
-
> Anatoly Podgoretsky © (13.04.10 16:12) [6]
CreateForm у TWebApplication не создаёт никаких форм и не инициализирует втрой передаваемый параметр.
-
> Плохиш (13.04.2010 19:35:11) [11]
Он создает datamodule
-
> Anatoly Podgoretsky © (13.04.10 20:21) [12] > > > Плохиш (13.04.2010 19:35:11) [11] > > Он создает datamodule
Вообще-то, в данном случае, WebModule, а уже в нём ищется требуемый интерфейс и создаётся компонент с реализацией.
-
> Он создает datamodule
Кстати, у автора никаких datamodule нету ;-)
-
> Плохиш (13.04.2010 21:36:14) [14]
TWebModule наследник от Тdatamodule
-
> Anatoly Podgoretsky © (13.04.10 21:40) [15] > TWebModule наследник от Тdatamodule
Да. Но, у автора проблема в том, что он наивно думает, что у webapplication CreateForm делает то же самое, что и в vcl, а она только регистрирует единственный класс webmodule в проекте. Создаётся его экземпляр уже в методе Run, а его переменная WM никогда не инициализируется.
PS. О создании веб-приложений очень подробно расписано в руководстве разработчика, там эта тема примерно четверть руководства занимает.
-
Плохиш, > А теперь переноси всё своё барахло из WebModule в реализацию > своего интерфейса TS1. Ибо, делфи создаёт наследника WebModule > не для того, что бы туда не думая всякий мусор пихали.
То есть неиспользовать webmodule, а создавать все компоненты ручками? Типа такого? function Ts1.GetDataFromBase2(s:AnsiString): AnsiString; stdcall;
var FbDatabase: TpFIBDatabase;
FbTransRead: TpFIBTransaction;
FbTransWrite: TpFIBTransaction;
FbFirms: TpFIBDataSet;
FbSql: TpFibQuery;
begin
Log('Начало функции');
FbDatabase:=TpFibDatabase.Create(nil);
try
with FbDatabase.DBParams do
begin
Add('user_name='+'SYSDBA');
Add('password='+'masterke');
Add('lc_ctype='+'WIN1251');
end;
FbDatabase.DatabaseName:='C:\Ruslan\...\Base\avtobase.fdb';
try
FbDatabase.Connected := True;
FbTransRead:=TpFibTransaction.Create(nil);
try
FbTransRead.DefaultDatabase:=FbDatabase;
FbSql:=TpFibQuery.Create(nil);
.................................
>Да. >Но, у автора проблема в том, что он наивно думает, что у webapplication >CreateForm делает то же самое, что и в vcl, а она только регистрирует >единственный класс webmodule в проекте. Создаётся его экземпляр уже в >методе Run, а его переменная WM никогда не инициализируется.
Да, именно так я и думал. > PS. О создании веб-приложений очень подробно расписано в > руководстве разработчика, там эта тема примерно четверть > руководства занимает.
Вы имеете ввиду книгу? Вот эту www.ozon.ru/context/detail/id/1135615/ ? Сейчас скачаю, почитаю. Спасибо за наводку.
-
> Rusland © (14.04.10 14:47) [17] > То есть неиспользовать webmodule, а создавать все компоненты > ручками? Типа такого?
Будь проще. Оставь webmodule так, как его создало, пусть занимается общим управлением. Удали свой TS1 и создай его заново, но не как "SOAP Server Interface", а как "SOAP Server Data Module".
> Вы имеете ввиду книгу? Вот эту www.ozon.ru/context/detail/id/1135615/? > Сейчас скачаю, почитаю. Спасибо за наводку.
Я имел в виду руководство из комплекта поставки, но и этой надеюсь достаточно будет, для начала.
-
А ветке место в "Corba и COM" :-)
-
Плохиш © (14.04.10 17:04) [19]
Раньше надо было говорить
-
> Будь проще. Оставь webmodule так, как его создало, пусть > занимается общим управлением. > Удали свой TS1 и создай его заново, но не как "SOAP Server > Interface", а как "SOAP Server Data Module".
Плохиш, большое вам спасибо. Помогло! Теперь не придется вручную создавать компоненты.
Уважаемые мастера, подскажите как передавать целиком датасет? (пока что только строку умею передавать из БД) Где про это почитать?
-
DeveloperGuide.pdf от Delphi7 разделы начиная с "Ch29: Using client datasets".
Ты вроде книгу скачал, неужели там нет этого?
-
Плохиш, "чукча не читатель, чукча писатель" :-D Сейчас буду более внимательно читать.
|