Конференция "Базы" » FibPlus в клиент-серверном приложении [D7, Firebird]
 
  • Rusland © (13.04.10 12:48) [0]
    Добрый день.
    Пишу клиент-вебсерверное приложение (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/ (серверная часть)
  • Медвежонок Пятачок © (13.04.10 13:04) [1]
    зачем это проверять, это и так из контекста ясно что не создан.
  • Anatoly Podgoretsky © (13.04.10 13:28) [2]
    Это проверять не надо, а надо делать так чтобы не проверять
  • Rusland © (13.04.10 15:38) [3]
    Медвежонок Пятачок, Anatoly Podgoretsky
    Ткните носом пожалуйста что и где прописать?
    У меня же прописано создание WM

    program WebServ1;

    {$APPTYPE CONSOLE}

    uses
     WebBroker,
     CGIApp,
     Unit1 in 'Unit1.pas' {WM: TWebModule},
     S1Intf in 'S1Intf.pas',
     S1Impl in 'S1Impl.pas';

    {$R *.res}

    begin
     Application.Initialize;
     Application.CreateForm(TWM, WM); // разьве этого недостаточно?
     Application.Run;
    end.

  • Медвежонок Пятачок © (13.04.10 15:49) [4]
    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); // разьве этого недостаточно?
  • Anatoly Podgoretsky © (13.04.10 16:08) [5]
    Вроде бы как бы достаточно, если только Ts1 не вызывается до создания WM или где нибудь WM не разрушается. И конечно все компоненты участвующие в процессе также созданы. А сообщение "Read of address 000000AC" говорит, что это не так. Дело к тому же может быть в обработчиках, может там что либо не в порядке, а не WM
    Сообственно ты код почти не показываешь.
  • Anatoly Podgoretsky © (13.04.10 16:12) [6]

    > Медвежонок Пятачок ©   (13.04.10 15:49) [4]

    Это к вопросу не относится, вот когда он будет делать isapi вот тогда будет по делу. А вот загадочный TS1 это интереснее, но информации о нем нет.
  • Rusland © (13.04.10 16:49) [7]
    Показать код не проблема. Вот для серверной части проекта.
    Код для S1Impl.pas
    unit S1Impl;

    interface

    uses InvokeRegistry, Types, XSBuiltIns, S1Intf, Unit1, Classes, SysUtils, FIBDatabase, pFIBDatabase, DB, FIBDataSet, pFIBDataSet, Unit2;

    type

     { TS1 }
     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; // тут получаю Access Violation
         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
    { Invokable classes must be registered }
      InvRegistry.RegisterInvokableClass(TS1);
    end.



    Код для S1Intf.pas
    unit S1Intf;

    interface

    uses InvokeRegistry, Types, XSBuiltIns, Unit1;

    type

     { Invokable interfaces must derive from IInvokable }
     TArrString = array of string;
     IS1 = interface(IInvokable)
     ['{181AF89B-CDAC-43FE-AF7F-83660617C558}']

     function GetTT(d:integer): TArrString; stdcall;
     function GiveX2(d:integer): integer; stdcall;
     function GetDataFromBase(s:AnsiString): AnsiString; stdcall;
       { Methods of Invokable interface must not use the default }
       { calling convention; stdcall is recommended }
     end;

    implementation

    initialization
     { Invokable interfaces must be registered }
     InvRegistry.RegisterInterface(TypeInfo(IS1));

    end.



    Код для Unit1
    unit 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
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     WM: TWM;

    implementation

    {$R *.dfm}

    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. Не стесняйтесь обзывать меня балбесом, но только помогите понять как писать вебсерверы с БД :)
  • Anatoly Podgoretsky © (13.04.10 16:53) [8]
    Разве TS1 можно не создавать?
  • Rusland © (13.04.10 17:27) [9]

    > Разве TS1 можно не создавать?


    Anatoly Podgoretsky, не знаю даже что ответить... Этот код генерирует сам BDS, если выбрать File -> New -> Other... -> WebServices -> SOAP Server Application (я лишь пытаюсь прикрутить подключение к БД).

    Если нужно создавать TS1, то где и как?

    Хочу заметить, что функция GiveX2 нормально вызывается из клиентского приложения и возвращает то что надо (исходное число умноженное на 2).
  • Плохиш © (13.04.10 19:26) [10]

    > Rusland ©   (13.04.10 16:49) [7]

    А теперь переноси всё своё барахло из WebModule в реализацию своего интерфейса TS1. Ибо, делфи создаёт наследника WebModule не для того, что бы туда не думая всякий мусор пихали.
  • Плохиш © (13.04.10 19:35) [11]

    > Anatoly Podgoretsky ©   (13.04.10 16:12) [6]

    CreateForm у TWebApplication не создаёт никаких форм и не инициализирует втрой передаваемый параметр.
  • Anatoly Podgoretsky © (13.04.10 20:21) [12]
    > Плохиш  (13.04.2010 19:35:11)  [11]

    Он создает datamodule
  • Плохиш © (13.04.10 21:33) [13]

    > Anatoly Podgoretsky ©   (13.04.10 20:21) [12]
    >
    > > Плохиш  (13.04.2010 19:35:11)  [11]
    >
    > Он создает datamodule

    Вообще-то, в данном случае, WebModule, а уже в нём ищется требуемый интерфейс и создаётся компонент с реализацией.
  • Плохиш © (13.04.10 21:36) [14]

    > Он создает datamodule

    Кстати, у автора никаких datamodule нету ;-)
  • Anatoly Podgoretsky © (13.04.10 21:40) [15]
    > Плохиш  (13.04.2010 21:36:14)  [14]

    TWebModule наследник от Тdatamodule
  • Плохиш © (14.04.10 00:24) [16]

    > Anatoly Podgoretsky ©   (13.04.10 21:40) [15]
    > TWebModule наследник от Тdatamodule

    Да.
    Но, у автора проблема в том, что он наивно думает, что у webapplication CreateForm делает то же самое, что и в vcl, а она только регистрирует единственный класс webmodule в проекте. Создаётся его экземпляр уже в методе Run, а его переменная WM никогда не инициализируется.

    PS. О создании веб-приложений очень подробно расписано в руководстве разработчика, там эта тема примерно четверть руководства занимает.
  • Rusland © (14.04.10 14:47) [17]
    Плохиш,

    > А теперь переноси всё своё барахло из 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/ ?
    Сейчас скачаю, почитаю. Спасибо за наводку.
  • Плохиш © (14.04.10 17:02) [18]

    > Rusland ©   (14.04.10 14:47) [17]
    > То есть неиспользовать webmodule, а создавать все компоненты
    > ручками? Типа такого?

    Будь проще. Оставь webmodule так, как его создало, пусть занимается общим управлением.
    Удали свой TS1 и создай его заново, но не как "SOAP Server Interface", а как "SOAP Server Data Module".

    > Вы имеете ввиду книгу? Вот эту www.ozon.ru/context/detail/id/1135615/?
    > Сейчас скачаю, почитаю. Спасибо за наводку.

    Я имел в виду руководство из комплекта поставки, но и этой надеюсь достаточно будет, для начала.
  • Плохиш © (14.04.10 17:04) [19]
    А ветке место в "Corba и COM" :-)
 
Конференция "Базы" » FibPlus в клиент-серверном приложении [D7, Firebird]
Есть новые Нет новых   [134433   +21][b:0][p:0.007]