Delphi: Clientdataset: EDatabaseError on .Open; with ProviderName set - delphi

So I'm having this code that processes what the client sends on a pattern. If he sends 'getBENUds', the server sends the DataSet for this table back using the SaveToString method.
Then, this is sent to the client. (I'm using Synapse).
procedure TTCPSocketThrd.Execute;
var s: String;
strm: TMemoryStream;
ADO_CON: TADOConnection;
ADO_QUERY: TADOQuery;
DS_PROV: TDataSetProvider;
DS_CLIENT: TClientDataSet;
begin
CoInitialize(nil);
Sock := TTCPBlockSocket.Create;
try
Sock.Socket := CSock;
Sock.GetSins;
with Sock do
begin
repeat
if terminated then break;
s := RecvTerminated(60000,'|');
if s = 'getBENUds' then
begin
//ini ADO_CON
ADO_CON := TADOConnection.Create(Form1);
ADO_CON.ConnectionString := 'not for public';
ADO_CON.LoginPrompt := false;
ADO_CON.Provider := 'SQLOLEDB.1';
ADO_CON.Open;
//ini ADO_QUERY
ADO_QUERY := TADOQuery.Create(ADO_CON);
ADO_QUERY.Connection := ADO_CON;
//ini DS_PROV
DS_PROV := TDataSetProvider.Create(ADO_CON);
DS_PROV.DataSet := ADO_QUERY;
//ini DS_CLIENT
DS_CLIENT := TClientDataSet.Create(ADO_CON);
DS_CLIENT.ProviderName := 'DS_PROV';
//SQLQUERY Abfrage
ADO_QUERY.SQL.Clear;
ADO_QUERY.SQL.Add('SELECT * FROM BENU');
ADO_QUERY.Open;
//DSCLIENTDATASET bauen
strm := TMemoryStream.Create;
DS_CLIENT.Open;
DS_CLIENT.SaveToStream(strm);
end
else if s = 'getBESTEds' then
...
The line it says: DS_CLIENT.Open an exception is thrown:
An exception has been thrown: class EDatabaseError. Text: 'missing data-provider or data package'.
The data-provider has been set as can be seen above to 'DS_PROV', so it has to be the missing data package.
But shouldn't the ClientDataSet get its data from the DataSetProvider which in turn gets it from the ADOQuery that gets the data from the database?
This is as far as I get with my level of knowledge. I hope its not too difficult, because in my eyes, everything I did was correct.

Use
DS_CLIENT.SetProvider(DS_PROV);
or after DS_PROV creation: (at this time your component has really no name)
DS_PROV.name := 'DS_PROV';

Related

Delphi service app crashes at a random time

I have a Delphi Service app. Indy TCP server and many clients (up to 50), ADO connection to Firebird and simply network exchange. App randomly crashes (may be workin 7 days, may be 1 hour) with next event (for example):
Имя сбойного приложения: rollcontrol.exe, версия: 1.1.20.2, метка времени: 0x60acd5f2
Имя сбойного модуля: ntdll.dll, версия: 6.3.9600.19678, метка времени: 0x5e82c0f7
Код исключения: 0xc0000005
Смещение ошибки: 0x00058def
Идентификатор сбойного процесса: 0x4178
or:
Имя сбойного приложения: rollcontrol.exe, версия: 1.1.1.9, метка времени: 0x607b239c
Имя сбойного модуля: msvcrt.dll, версия: 7.0.9600.16384, метка времени: 0x52158ff5
Код исключения: 0xc0000005
Смещение ошибки: 0x00009e80
All jobs in app makes in anonimius threads or in tcp/ip connections threads. All code in each thread executed in try except statments. There no memory leaks or growing threads count. The main code of service thread very simple:
procedure TRollControl_Svc.ServiceExecute(Sender: TService);
begin
while not Terminated do
try
ServiceThread.ProcessRequests(False);
ServiceThread.Sleep(100);
except
on e : exception do LogException('ServiceExecute', E);
end;
end;
How I can handled this exception and prevent app crash? How it possible to crash service thread with two simple lines of code?
Thanks
UPDATE: Example of connections to DB:
function TRollControl_Svc.GetNodeIdByIP(ip: string): integer;
Var
SQLConnection : TADOConnection;
SQLQuery : TADOQuery;
Thread : TThread;
fResult : integer;
begin
fResult := 0;
try
Thread := nil;
Thread := TThread.CreateAnonymousThread(
procedure
begin
try
SQLConnection := nil;
SQLQuery := nil;
CoInitialize(nil);
SQLConnection := TADOConnection.Create(nil);
SQLConnection.ConnectionString := 'Provider=MSDASQL.1;Password=' + Psw + ';Persist Security Info=True;User ID=' + Usr + ';Data Source=' + Srv ;
SQLConnection.LoginPrompt := false;
SQLQuery := TADOQuery.Create(nil);
SQLQuery.Connection := SQLConnection;
SQLQuery.LockType := ltReadOnly;
try SQLConnection.Open; except SQLConnection.Open; end;
SQLConnection.BeginTrans;
SQLQuery.Close;
SQLQuery.SQL.Text := 'select nodes.* from nodes where nodes.ip = :ip';
SQLQuery.Parameters.ParamByName('ip').Value := ip;
try SQLQuery.Open; except SQLQuery.Open; end;
if SQLQuery.IsEmpty then exit;
fResult := SQLQuery.FieldByName('ID').AsInteger;
if SQLConnection.InTransaction then
SQLConnection.CommitTrans;
finally
TryFree(SQLQuery);
TryFree(SQLConnection);
CoUninitialize;
end;
end
);
Thread.FreeOnTerminate := false;
Thread.Start;
Thread.WaitFor;
finally
TryFree(Thread);
end;
result := fResult;
end;
Error Handling
This isn't an answer as to what is causing your problem, but I thought it probably wouldn't be clear in a comment.
In languages that support structured exception handling the language gives the programmer an opportunity to fail gracefully when things don't work. That's not how you are using it. From your example anonymous thread you have:
try SQLConnection.Open; except SQLConnection.Open; end;
So you are told that the connection can't be made and instead of responding to that situation you go ahead and attempt to connect again. There are lots of reasons why a connection may not work, some of those are transient so the attempt may work a little later but if you simply try doing it again without any pause it seems reasonable to expect it to fail again.
It's obviously important to catch errors, but you have to have appropriate failure paths.
I have no way of knowing if this is related to what's actually going wrong.
I found the reason. The problem was in the ADO source codes (Data.Win.ADODB.pas):
procedure RefreshFromOleDB;
var
I: Integer;
ParamCount: ULONG_PTR;
ParamInfo: PDBParamInfoArray;
NamesBuffer: POleStr;
Name: WideString;
Parameter: _Parameter;
Direction: ParameterDirectionEnum;
OLEDBCommand: ICommand;
OLEDBParameters: ICommandWithParameters;
CommandPrepare: ICommandPrepare;
begin
OLEDBCommand := (Command.CommandObject as ADOCommandConstruction).OLEDBCommand as ICommand;
OLEDBCommand.QueryInterface(ICommandWithParameters, OLEDBParameters);
OLEDBParameters.SetParameterInfo(0, nil, nil); // ----- Error here
if Assigned(OLEDBParameters) then
begin
ParamInfo := nil;
NamesBuffer := nil;
try
OLEDBCommand.QueryInterface(ICommandPrepare, CommandPrepare);
if Assigned(CommandPrepare) then CommandPrepare.Prepare(0);
if OLEDBParameters.GetParameterInfo(ParamCount, PDBPARAMINFO(ParamInfo), #NamesBuffer) = S_OK then
for I := 0 to ParamCount - 1 do//
begin
{ When no default name, fabricate one like ADO does }
if ParamInfo[I].pwszName = nil then
Name := 'Param' + IntToStr(I+1) else { Do not localize }
Name := ParamInfo[I].pwszName;
{ ADO maps DBTYPE_BYTES to adVarBinary }
if ParamInfo[I].wType = DBTYPE_BYTES then ParamInfo[I].wType := adVarBinary;
{ ADO maps DBTYPE_STR to adVarChar }
if ParamInfo[I].wType = DBTYPE_STR then ParamInfo[I].wType := adVarChar;
{ ADO maps DBTYPE_WSTR to adVarWChar }
if ParamInfo[I].wType = DBTYPE_WSTR then ParamInfo[I].wType := adVarWChar;
Direction := ParamInfo[I].dwFlags and $F;
{ Verify that the Direction is initialized }
if Direction = adParamUnknown then Direction := adParamInput;
Parameter := Command.CommandObject.CreateParameter(Name, ParamInfo[I].wType, Direction, ParamInfo[I].ulParamSize, EmptyParam);
Parameter.Precision := ParamInfo[I].bPrecision;
Parameter.NumericScale := ParamInfo[I].bScale;
//if ParamInfo[I].dwFlags and $FFFFFFF0 <= adParamSigned + adParamNullable + adParamLong then
Parameter.Attributes := ParamInfo[I].dwFlags and $FFFFFFF0; { Mask out Input/Output flags }
AddParameter.FParameter := Parameter;
end;
finally
if Assigned(CommandPrepare) then CommandPrepare.Unprepare;
if (ParamInfo <> nil) then GlobalMalloc.Free(ParamInfo);
if (NamesBuffer <> nil) then GlobalMalloc.Free(NamesBuffer);
end;
end;
end;
Line
OLEDBParameters.SetParameterInfo(0, nil, nil)
executed before
if Assigned(OLEDBParameters)
I moved this line after checking on nil and all working fine
I managed to isolate the problem. Errors occur periodically when working with ADO. If I try to use TADOQuery objects again, the application more susceptible to crashes. What I've done:
System.NeverSleepOnMMThreadContention: = false;
Significantly reduces errors when working with ADO
All uses of TADOQuery are single use.
For example it was:
for ii := 0 to SettingsXML.Root.NamedItem['sql_clear_base'].NamedItem['XML'].Count - 1 do
begin
try
SQLQuery.Close;
SQLQuery.SQL.Text := SettingsXML.Root.NamedItem['sql_clear_base'].NamedItem['XML'][ii].AsString;
SQLQuery.ExecSQL;
except
on e : exception do LogException('ClearBase', '', E);
end;
end;
Became:
for ii := 0 to SettingsXML.Root.NamedItem['sql_clear_base'].NamedItem['XML'].Count - 1 do
begin
SQLQuery := nil;
try
SQLQuery := TADOQuery.Create(nil);
SQLQuery.Connection := SQLConnection;
try
SQLQuery.Close;
SQLQuery.SQL.Text := SettingsXML.Root.NamedItem['sql_clear_base'].NamedItem['XML'][ii].AsString;
SQLQuery.ExecSQL;
except
on e : exception do LogException('ClearBase', '', E);
end;
finally
TryFree(SQLQuery);
end;
end;
I make self-control:
main procces started as windows service (process A)
process A starts a copy of itself as B
one per minutes A check if B alive and restart if not
one per minutes B check if A alive and restart if not
check - simple TCP packet and answer
For example:
TThread.CreateAnonymousThread(
procedure
var tcpClient : TidTCPClient;
begin
tcpClient := nil;
LastKeepAlive := Date + Time;
while ServerMode do
begin
try
if not Assigned(tcpClient) then
begin
tcpClient := TIdTCPClient.Create(nil);
tcpClient.Host := '127.0.0.1';
tcpClient.Port := RollControl_Svc.TCPServer.Bindings[0].Port;
tcpClient.Connect;
tcpClient.IOHandler.ReadTimeout := 1000;
end;
tcpClient.IOHandler.Write(START_PACKET + #0 + END_PACKET);
tcpClient.IOHandler.ReadString(3);
LastKeepAlive := Date + Time;
except
TryFree(tcpClient);
end;
sleep(15 * 1000);
end;
end).Start;
TThread.CreateAnonymousThread(
procedure
Var Res: TRequestResult;
begin
while ServerMode do
begin
if Date + Time - LastKeepAlive > OneMinute then
begin
Res.Clear('', '');
Res.Nodes_ID := -1;
Res.Data_In := 'KeepAlive';
Res.Data_Out := 'Exception: ExitProcess(1)';
try
Log(Res, true);
finally
ExitProcess(1);
end;
end;
sleep(1000);
end;
end).Start;
P.S. Local tests never crashed applications. The program simply proceed a million requests (connect, request, disconnect), there are no memory leaks or failures. On several clients servers are crashed. In the future I want to port to Lazarus to use ODBC directly insteed ADO

Revisited: TClientDataset "Missing data provider or data packet"

With a dynamically created TFDQuery,TClientDataSet, and TDataSetProvider I bump into the "Missing data provider or data packet" with this code:
procedure ResetSavedPasswords(ADataModuleDataBaseAdmin : TDataModuleDataBaseAdmin);
var
lQuery : TFDQuery;
lCDS : TClientDataSet;
lProvider : TDataSetProvider;
begin
lFrmBezig := TFormBezig.Create(nil);
lQuery := TFDQuery.Create(nil);
lProvider := TDataSetProvider.Create(Application);
lCDS := TClientDataSet.Create(nil);
try
lQuery.Connection := ADataModuleDataBaseAdmin.FDConnectionTimeTell;
lQuery.CachedUpdates := true;
lProvider.Options := lProvider.Options - [poUseQuoteChar];
lProvider.DataSet := lQuery;
lProvider.Name := 'prvResetSavedPW';
lCDS.ProviderName := lProvider.Name;
lQuery.SQL.Text := Format('select %s,%s from <owner>%s',[sMedMedID,sMedSavedPassword,SMedTabelNaam]),ADataModuleDataBaseAdmin;
lCDS.Open;
Note that the created TDataSetProvider has an owner, based on this answer:
If DatasetProvider has no owner, ClientDataSet can not obtain a reference to the provider
But I still get the error. Opening the TFDQuery first shows me it has data.
What can be the reason?
Using FireDAC with Delphi 10.4. Sydney in a Win32 app.
It turns out that TClientDataSet needs an owner too:
lCDS := TClientDataSet.Create(Application);
This is obvious from the code that triggered the exception:
function TCustomClientDataSet.GetAppServer: IAppServer;
var
ProvComp: TComponent;
DS: TObject;
begin
if not HasAppServer then
begin
if ProviderName <> '' then
if Assigned(RemoteServer) then
FAppServer := RemoteServer.GetServer
else if Assigned(ConnectionBroker) then
FAppServer := ConnectionBroker.GetServer
else
begin
if Assigned(Owner) then
begin
ProvComp := Owner.FindComponent(ProviderName);
if Assigned(ProvComp) and (ProvComp is TCustomProvider) then
begin
DS := GetObjectProperty(ProvComp, 'DataSet');
if Assigned(DS) and (DS = Self) then
DatabaseError(SNoCircularReference, Self);
FAppServer := TLocalAppServer.Create(TCustomProvider(ProvComp));
end;
end;
end;
if not HasAppServer then
DatabaseError(SNoDataProvider, Self);
end;
Result := FAppServer;
end;
The Assigned(Owner) fails, so the code does not bother looking for the TDataSetProvider

Transfer of Large Stream from server to client fails

All,
I am working on a new datasnap project based on the example project located in C:\Users\Public\Documents\Embarcadero\Studio\18.0\Samples\Object Pascal\DataSnap\FireDAC_DBX.
I am trying to transfer a large stream (1,606,408 bytes) from datasnap server to client. I am running into what appears to be a common issue and that is that the entire stream does not make it to the client.
Here is my server code:
//Returns Customer Info
function TServerMethods.GetBPInfo(CardCode : String): TStringStream;
begin
Result := TStringStream.Create;
try
qBPInfo.Close;
if CardCode.Trim = '' then
qBPInfo.ParamByName('ParmCardCode').AsString := '%%'
else
qBPInfo.ParamByName('ParmCardCode').AsString := '%' + CardCode + '%';
qBPInfo.Open;
FDSchemaAdapterBPInfo.SaveToStream(Result, TFDStorageFormat.sfBinary);
Result.Position := 0;
// Result.SaveToFile('output.adb');
except
raise;
end;
end;
Here is my client code:
procedure TdmDataSnap.GetBPInfo(CardCode : String);
var
LStringStream : TStringStream;
begin
dmDataSnap.FDStoredProcBPInfo.ParamByName('CardCode').AsString := CardCode;
FDStoredProcBPInfo.ExecProc;
LStringStream := TStringStream.Create(FDStoredProcBPInfo.ParamByName('ReturnValue').asBlob);
//LStringStream.Clear;
//LStringStream.LoadFromFile('Output.adb');
try
if LStringStream <> nil then
begin
LStringStream.Position := 0;
try
DataModuleFDClient.FDSchemaAdapterBP.LoadFromStream(LStringStream, TFDStorageFormat.sfBinary);
except
on E : Exception do
showmessage(e.Message);
end;
end;
finally
LStringStream.Free;
end;
end;
You will see the stream save and load code; that is how I determined that the server was getting the entire result set into the stream, and that the client could handle the entire result set and display it properly.
So smaller streams transfer just fine, but this big one, when examined in the ide debugger, does not start with the 65,66,68,83 characters and the load fails with the error, '[FireDAC][Stan]-710. Invalid binary storage format'.
I know from extended Googling that there are work-arounds for this, but I do not understand how to apply the workarounds to my case, with the use of Tfdstoredproc and TfdSchemaAdaptor components. I'm trying to stay with this coding scheme.
How do I adapt this code to correctly receive large streams?
Update 1:
Ok, I tried strings and Base64 encoding. It didn't work.
Client Code:
procedure TdmDataSnap.GetBPInfo(CardCode : String);
var
LStringStream : TStringStream;
TempStream : TStringStream;
begin
dmDataSnap.FDStoredProcBPInfo.ParamByName('CardCode').AsString := CardCode;
FDStoredProcBPInfo.ExecProc;
try
TempStream := TStringStream.Create;
TIdDecoderMIME.DecodeStream(FDStoredProcBPInfo.ParamByName('ReturnValue').asString,TempStream);
if TempStream <> nil then
begin
TempStream.Position := 0;
try
DataModuleFDClient.FDSchemaAdapterBP.LoadFromStream(TempStream, TFDStorageFormat.sfBinary);
except
on E : Exception do
showmessage(e.Message);
end;
end;
finally
TempStream.Free;
end;
end;
Here is my server code:
//Returns Customer Info
function TServerMethods.GetBPInfo(CardCode : String): String;
var
TempStream : TMemoryStream;
OutputStr : String;
begin
Result := '';
TempStream := TMemoryStream.Create;
try
try
qBPInfo.Close;
if CardCode.Trim = '' then
qBPInfo.ParamByName('ParmCardCode').AsString := '%%'
else
qBPInfo.ParamByName('ParmCardCode').AsString := '%' + CardCode + '%';
qBPInfo.Open;
FDSchemaAdapterBPInfo.SaveToStream(TempStream, TFDStorageFormat.sfBinary);
TempStream.Position := 0;
OutputStr := IdEncoderMIMEBPInfo.EncodeStream(TempStream);
Result := OutputStr
except
raise;
end;
finally
TempStream.Free;
end;
end;
The result is the same.

Using Outlook Contacts In Delphi XE7

I am trying to get a list of all outlook contacts using delphi.
I found a couple of examples, all seemed to be outdated or flawed.
Currently I have the following code, but when I excecute the command at runtime I get the below error:
Code:
procedure Tinvite_friends.BitBtn2Click(Sender: TObject);
const
olFolderContacts = $0000000A;
var
outlook, NameSpace, Contacts, Contact: OleVariant;
i: Integer;
begin
Try
outlook:=GetActiveOleObject('Outlook.Application');
Except
outlook:=CreateOleObject('Outlook.Application');
End;
NameSpace := outlook.GetNameSpace('MAPI');
Contacts := NameSpace.GetDefaultFolder(olFolderContacts);
for i := 1 to Contacts.Items.Count do
begin
Contact := Contacts.Items.Item(i);
{now you can read any property of contact. For example, full name and
email address}
ShowMessage(Contact.FullName + ' <' + Contact.Email1Address + '>');
end;
Outlook := UnAssigned;
end;
Error Message:
Project appname.exe raised exception class EOLeSysError with message 'Invalid class string'.
The project does not get passed the below code before throwing the error.
Try
outlook:=GetActiveOleObject('Outlook.Application');
Except
outlook:=CreateOleObject('Outlook.Application');
End;
Is there an effective way to get a list of all contacts from outlook imported to a memo for example?
Maybe it's case sensitivity? I test for outlook.application:
const
scxOutlookApp = 'outlook.application';
scxNameSpace = 'MAPI';
function TDataModuleSyncOutlook.ConnectToOutlook(AUserSMTP: String = ''): Boolean;
var
lRecipient,
lVar : OleVariant;
lLog,
lLoginSMTP: String;
begin
Result := false;
FWasCreated := False; // Breakpoint 'Ignore subsequent exceptions'
try
FOutlookApp := GetActiveOleObject(scxOutlookApp); // Application object
Result := True;
except
try
FOutlookApp := CreateOleObject(scxOutlookApp);
FWasCreated := True;
Result := True;
except
on E:Exception do TSyncLogger.LogError(E.Message);
end;
end;
if Result then // Breakpoint 'Handle subsequent exceptions'
begin
FNameSpace := FOutlookApp.GetNamespace(scxNameSpace);
// Solution from http://stackoverflow.com/questions/18053110/retrieve-outlook-logged-in-user-smtp-address-after-connecting-through-ole/
lLog := Format('Connected to Outlook; Application.DefaultProfilename: %s, Application.Name: %s, Application.Version: %s, NameSpace.CurrentProfileName: %s, NameSpace.ExchangeMailboxServerName: %s, NameSpace.Type: %s',
[FOutlookApp.DefaultProfileName,
FOutlookApp.Name,
FOutlookApp.Version,
FNameSpace.CurrentProfileName,
FNameSpace.ExchangeMailboxServerName,
FNameSpace.Type]);
TSyncLogger.LogDetail(lLog);
lVar := FOutlookApp.Session; // NameSpace object for the current session
if not VarIsClear(lVar) then lVar := lVar.CurrentUser; // Recipient object for the currently logged-on user
if not VarIsClear(lVar) then lVar := lVar.AddressEntry; // AddressEntry object for the recipient
if not VarIsClear(lVar) then lVar := lVar.GetExchangeUser; // Returns an ExchangeUser object that represents the AddressEntry
if not VarIsClear(lVar) then lVar := lVar.PrimarySmtpAddress; // String representing the SMTP address for the ExchangeUser
if not VarIsClear(lVar) then
begin
lLoginSMTP := FOutlookApp.Session.CurrentUser.AddressEntry.GetExchangeUser.PrimarySmtpAddress;
TSyncLogger.LogDetail('Primary Exchange SMTP address detected as: ' + lLoginSMTP);
end
else
begin
TSyncLogger.LogError(sErrNoExchangeAccount);
DisConnectFromOutlook;
Exit;
end;
if LowerCase(AUserSMTP) <> Lowercase(lLoginSMTP) then
begin // Open shared calendar if it's a different user
lRecipient := FNameSpace.CreateRecipient(AUserSMTP);
try
FCalendarFolder := FNameSpace.GetSharedDefaultFolder(lRecipient, olFolderCalendar);
lLog := Format('Logging in as different user (%s), created recipient for %s, GetSharedDefaultFolder folder path = %s',[AUserSMTP,lRecipient.Address,FCalendarFolder.FolderPath]);
TSyncLogger.LogAlways(lLog);
except
on E:Exception do
begin
Result := false;
TSyncLogger.LogError(Format(sErrOpenGedeeldeAgenda,[AUserSMTP]));
end;
end;
end
else // ... otherwise open default calendar folder
begin
FCalendarFolder := FNameSpace.GetDefaultFolder(olFolderCalendar);
TSyncLogger.LogDetail('Opened default calendar folder, folder path = ' + FCalendarFolder.FolderPath);
end;
end;
FOleInitialized := Result;
if Result then TSyncLogger.LogDetail('Connected to Outlook') else TSyncLogger.LogAlways('Connection to Outlook failed');
end;
Notes:
1. This opens the default calendar for any user, but you would not need to go that far (besides, your issue is earlier)
2. TSyncLogger is our logging handler
3. FOleInitialized, FWasCreated: Boolean; FOutlookApp, FNameSpace, FCalendarFolder: OleVariant; are some private properties we maintain
4. Essential to this code is that it first does a GetActiveOleObject to catch a running instance of Outlook; if that fails it does a CreateOleObject

What is real web-url for mORMot web-service?

Please help to understand about routing and web-url of web-service below.
type
TAirportService = class(TInterfacedObject, IAirportService)
public
procedure GetAirportDefinition(const AirPortID: integer; out Definition: TDTOAirportDefinition);
end;
procedure TAirportService.GetAirportDefinition(const AirPortID: integer;
out Definition: TDTOAirportDefinition);
begin
// create an object from static data
// (real application may use database and complex code to retrieve the values)
with Definition.Airport.Add do begin
Location := 'LAX';
Terminal := TRawUTF8DynArrayFrom(['terminalA', 'terminalB', 'terminalC']);
Gate := TRawUTF8DynArrayFrom(['gate1', 'gate2', 'gate3', 'gate4', 'gate5']);
BHS := 'Siemens';
DCS := 'Altiea';
end;
with Definition.Airline.Add do begin
CX := TRawUTF8DynArrayFrom(['B777', 'B737', 'A380', 'A320']);
QR := TRawUTF8DynArrayFrom(['A319', 'A380', 'B787']);
ET := '380';
SQ := 'A320';
end;
Definition.GroundHandler := TRawUTF8DynArrayFrom(['Swissport','SATS','Wings','TollData']);
end;
procedure StartWebService();
var
aModel: TSQLModel;
aDB: TSQLRestServer;
aServer: TSQLHttpServer;
begin
// set the logs level to only important events (reduce .log size)
TSQLLog.Family.Level := LOG_STACKTRACE+[sllInfo,sllServer];
// initialize the ORM data model
aModel := TSQLModel.Create([]);
try
// create a fast in-memory ORM server
aDB := TSQLRestServerFullMemory.Create(aModel,'test.json',false,false);
try
// register our TAirportServer implementation
// aDB.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculatorXML)],sicShared);
aDB.ServiceRegister(TAirportService,[TypeInfo(IAirportService)],sicShared);
// launch the HTTP server
aServer := TSQLHttpServer.Create('8092', [aDB], '+', useHttpApiRegisteringURI);
try
aServer.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
writeln('Background server is running'#10);
write('Press [Enter] to close the server.');
ConsoleWaitForEnterKey;
finally
aServer.Free;
end;
finally
aDB.Free;
end;
finally
aModel.Free;
end;
end;
I try to call follow web-urls:
http://localhost:8092/root/AirportService/GetAirportDefinition?AirPortID=1
http://localhost:8092/root/AirportService.GetAirportDefinition?AirPortID=1
http://localhost:8092/root/AirportService/GetAirportDefinition
http://localhost:8092/AirportService/GetAirportDefinition?AirPortID=1
http://localhost:8092/AirportService.GetAirportDefinition?AirPortID=1
http://localhost:8092/AirportService/GetAirportDefinition
but every time I get:
{
"errorCode":400,
"errorText":"Bad Request"
}
or Bad request
Where am I wrong?
A was wrong, really urls below works as needed:
http://localhost:8092/root/AirportService/GetAirportDefinition?AirPortID=1
http://localhost:8092/root/AirportService.GetAirportDefinition?AirPortID=1

Resources