You are not logged in.
Hi,
i write my first interface service method.
define the interface
IServiceDocumento = interface(IInvokable)['{6B7E89EC-34B0-43A6-9C81-86A324FC1DF9}']
function EmettiDocumento(aDocumento: TSQLDocumento): Integer;
function AnnullaDocumento(aDocumento: TSQLDocumento): Integer;
function ModificaDocumento(aDocumento: TSQLDocumento): Integer;
end;
implement the service in the server
TServiceDocumento = class(TInterfacedObject, IServiceDocumento)
public
function EmettiDocumento(aDocumento: TSQLDocumento): Integer;
function AnnullaDocumento(aDocumento: TSQLDocumento): Integer;
function ModificaDocumento(aDocumento: TSQLDocumento): Integer;
end;
register services on server and on client
self.Server.ServiceRegister(TServiceDocumento, [TypeInfo(IServiceDocumento)], sicSingle);
self.Client.ServiceRegister([TypeInfo(IServiceDocumento)], sicSingle);
use the service on client side
procedure TSQLDocumento.ComputeFieldsBeforeWrite(aRest: TSQLRest;
aOccasion: TSQLEvent);
var I: IServiceDocumento;
begin
inherited;
if aRest.Services['ServiceDocumento'].Get(I) then
begin
case aOccasion of
seAdd: I.EmettiDocumento(self);
seUpdate: I.ModificaDocumento(self);
seDelete: I.AnnullaDocumento(self);
end;
end;
end;
error:
TInterfacedObjectFakeClient.FakeCall(IServiceDocumento.EmettiDocumento) failed
errorCode: 400
errorText: SingleExecution Failed (probably due to bad input parameters) for IServiceDocumento.EmettiDocumento
where i mistake?
thanks,
Emanuele
Offline
anyone can help me to solve this problem?
thanks
Offline
hi ab,
no, the debugger don't reach TServiceDocumento.EmettiDocumento() implementation methods.
authentication is enabled, i use setUser on client side.
Offline
Put a breakpoint in TSQLRestRoutingREST.ExecuteSOAByInterface
and try to find out what occurs.
Also enable the logs on client and server side, and check them.
You would definitively find useful information in the logs.
Offline
i try to find in TSQLRestRoutingREST.ExecuteSOAByInterface but i don't know what to search...
this is the log
TSynLog 1.18.1341 FTS3 2015-05-19T14:22:41
20150519 14224114 EXC EInterfaceFactoryException ("TInterfacedObjectFakeClient.FakeCall(IServiceDocumento.ModificaDocumento) failed: '{\r\n\"errorCode\":400,\r\n\"errorText\":\"Single execution failed (probably due to bad input parameters) for IServiceDocumento.ModificaDocumento\"\r\n}'") at 007D229F stack trace API 006BB508 006BB530 0040AB04 76FF0083 76FF07FF 007D229F 007D2563 007D303E
can help you to help me?
Offline
What is the log on the server side? with detailed map debugging information enabled, if possible.
Use step by step debugging in TSQLRestRoutingREST.ExecuteSOAByInterface:
- does it reach TSQLRestServerURIContext.InternalExecuteSOAByInterface?
- what is the ServiceMethodIndex value?
- does it reach TServiceFactoryServer.ExecuteMethod?
BTW, why are you using sicSingle, and not sicShared as interface execution type?
Offline
how can enabled map debugging information?
the step by step reach TSQLRestServerURIContext.InternalExecuteSOAByInterface
ServiceMethodIndex is 0
the debugger reach TServiceFactoryServer.ExecuteMethod until
if not fInterface.fMethods[Ctxt.ServiceMethodIndex].InternalExecute(
[PAnsiChar(Inst.Instance)+entry^.IOffset],Ctxt.ServiceParameters,
WR,Ctxt.Call.OutHead,Ctxt.Call.OutStatus,
fExecution[Ctxt.ServiceMethodIndex].Options,
Ctxt.ForceServiceResultAsJSONObject,
{$ifdef LVCL}nil{$else}fBackgroundThread{$endif},
Ctxt.ExecuteCallback) then begin
Error('execution failed (probably due to bad input parameters)');
exit; // wrong request
end;
i try with sicShared with the same result.
Offline
And within the InternalExecute() ?
Do Ctxt.ServiceParameters content seems correct?
You enable the detailed map debugging in formation from the Project / Options.
Offline
Ctxt.ServiceParameters contains the TSQLRecord as Json, i think its correct.
Offline
i think the problem is here...
in the function TServiceMethod.InternalExecute
case ValueType of
smvObject: begin
Par := JSONToObject(Objects[IndexVar],Par,valid); <---- is not valid!! why?!
if not valid then
exit;
IgnoreComma(Par);
end;
any idea?
Offline
step by step parsing properties i found that the error is in RiepilogoIVA property.
this is the Json value
'{"ID":0,"CodiceDocumento":"","TipoDocumento":"","Numero":"","Data":135243497472,"CedentePrestatore":{"RagioneSociale":"","CodiceFiscale":"","PartitaIva":"","RegimeFiscale":"","Indirizzo":"","NumeroCivico":"","CAP":"","Comune":"","Provincia":"","Nazione":"","UfficioREA":"","NumeroREA":"","CapitaleSociale":0,"SocioUnitco":"","StatoLiquidazione":"","Telefono":"","Fax":"","eMail":""},"CessionarioCommittente":{"RagioneSociale":"","CodiceFiscale":"","PartitaIva":"","Indirizzo":"","NumeroCivico":"","CAP":"","Comune":"","Provincia":"","Nazione":""},"RagioneSociale":"","CodiceFiscale":"","PartitaIva":"","Indirizzo":"","NumeroCivico":"","CAP":"","Comune":"","Provincia":"","Nazione":"","TipoRitenuta":"","ImportoRitenuta":0,"AliquotaRitenuta":0,"CausalePagamento":"","BolloVirtuale":"","ImportoBollo":0,"PercentualeScontoMaggiorazione":0,"ImportoScontoMaggiorazione":0,"Arrotondamento":0,"CausaleDocumento":"","Art73":false,"Vettore":{"RagioneSociale":"","CodiceFiscale":"","PartitaIva":"","Indirizzo":"","NumeroCivico":"","CAP":"","Comune":"","Provincia":"","Nazione":"","NumeroLicenzaGuida":""},"MezzoTrasporto":"","CausaleTrasporto":"","NumeroColli":0,"AspettoColli":"","UnitaMisuraPesoColli":"","PesoColli":0,"DataOraRitiro":127489671168,"DataInizioTrasporto":127489671168,"IndirizzoConsegna":"","NumeroCivicoConsegna":"","CAPConsegna":"","ComuneConsegna":"","ProvinciaConsegna":"","NazioneConsegna":"","DataOraConsegna":127489671168,"CondizioniPagamento":"","DettagliPagamento":[],"RigheDocumento":[],"RiepilogoIVA":[],"Imponibile":0,"Imposta":0,"Totale":0,"DataCreazione":135243570155,"CreatoDa":"Admin","UltimaModifica":135243570155,"ModificatoDa":""}]'
and this is the TSQLRecord Definition
TSQLDocumento = class (TSQLBase)
private
FTipoDocumento: RawUTF8;
FCedentePrestatore: TAnagraficaCedentePrestatore;
FCessionarioCommittente: TAnagraficaCessionarioCommittente;
FNumero: RawUTF8;
FData: TTimeLog;
FCodiceDocumento: RawUTF8;
FTipoRitenuta: RawUTF8;
FAliquotaRitenuta: Double;
FImportoRitenuta: Double;
FCausalePagamento: RawUTF8;
FBolloVirtuale: RawUTF8;
FImportoBollo: Double;
FPercentualeScontoMaggiorazione: Double;
FImportoScontoMaggiorazione: Double;
FArrotondamento: Double;
FCausaleDocumento: RawUTF8;
FArt73: Boolean;
FVettore: TAnagraficaVettore;
FMezzoTrasporto: RawUTF8;
FCausaleTrasporto: RawUTF8;
FNumeroColli: Integer;
FAspettoColli: RawUTF8;
FUnitaMisuraPesoColli: RawUTF8;
FPesoColli: Double;
FNazioneConsegna: RawUTF8;
FComuneConsegna: RawUTF8;
FNumeroCivicoConsegna: RawUTF8;
FProvinciaConsegna: RawUTF8;
FDataOraRitiro: TTimeLog;
FCAPConsegna: RawUTF8;
FIndirizzoConsegna: RawUTF8;
FDataOraConsegna: TTimeLog;
FCondizioniPagamento: RawUTF8;
FDettagliPagamento: TDettagliPagamento;
FRigheDocumento: TRigheDocumento;
FDataInizioTrasporto: TTimeLog;
function getRiepilogoIVA: TRiepilogoIVA;
function getImponibile: Double;
function getImposta: Double;
function getTotale: Double;
//function getRagioneSociale: RawUTF8;
public
procedure ComputeFieldsBeforeWrite(aRest: TSQLRest; aOccasion: TSQLEvent); override;
published
property CodiceDocumento: RawUTF8 index 4 read FCodiceDocumento write FCodiceDocumento;
property TipoDocumento: RawUTF8 index 40 read FTipoDocumento write FTipoDocumento;
property Numero: RawUTF8 index 30 read FNumero write FNumero;
property Data: TTimeLog read FData write FData;
property CedentePrestatore: TAnagraficaCedentePrestatore read FCedentePrestatore write FCedentePrestatore;
property CessionarioCommittente: TAnagraficaCessionarioCommittente read FCessionarioCommittente write FCessionarioCommittente;
property RagioneSociale: RawUTF8 read FCessionarioCommittente.RagioneSociale write FCessionarioCommittente.RagioneSociale;
property CodiceFiscale: RawUTF8 read FCessionarioCommittente.CodiceFiscale write FCessionarioCommittente.CodiceFiscale;
property PartitaIva: RawUTF8 read FCessionarioCommittente.PartitaIva write FCessionarioCommittente.PartitaIva;
property Indirizzo: RawUTF8 read FCessionarioCommittente.Indirizzo write FCessionarioCommittente.Indirizzo;
property NumeroCivico: RawUTF8 read FCessionarioCommittente.NumeroCivico write FCessionarioCommittente.NumeroCivico;
property CAP: RawUTF8 read FCessionarioCommittente.CAP write FCessionarioCommittente.CAP;
property Comune: RawUTF8 read FCessionarioCommittente.Comune write FCessionarioCommittente.Comune;
property Provincia: RawUTF8 read FCessionarioCommittente.Provincia write FCessionarioCommittente.Provincia;
property Nazione: RawUTF8 read FCessionarioCommittente.Nazione write FCessionarioCommittente.Nazione;
property TipoRitenuta: RawUTF8 index 4 read FTipoRitenuta write FTipoRitenuta;
property ImportoRitenuta: Double read FImportoRitenuta write FImportoRitenuta;
property AliquotaRitenuta: Double read FAliquotaRitenuta write FAliquotaRitenuta;
property CausalePagamento: RawUTF8 index 2 read FCausalePagamento write FCausalePagamento;
property BolloVirtuale: RawUTF8 index 2 read FBolloVirtuale write FBolloVirtuale;
property ImportoBollo: Double read FImportoBollo write FImportoBollo;
property PercentualeScontoMaggiorazione: Double read FPercentualeScontoMaggiorazione write FPercentualeScontoMaggiorazione;
property ImportoScontoMaggiorazione: Double read FImportoScontoMaggiorazione write FImportoScontoMaggiorazione;
property Arrotondamento: Double read FArrotondamento write FArrotondamento;
property CausaleDocumento: RawUTF8 read FCausaleDocumento write FCausaleDocumento;
property Art73: Boolean read FArt73 write FArt73;
property Vettore: TAnagraficaVettore read FVettore write FVettore;
property MezzoTrasporto: RawUTF8 index 80 read FMezzoTrasporto write FMezzoTrasporto;
property CausaleTrasporto: RawUTF8 index 100 read FCausaleTrasporto write FCausaleTrasporto;
property NumeroColli: Integer read FNumeroColli write FNumeroColli;
property AspettoColli: RawUTF8 index 100 read FAspettoColli write FAspettoColli;
property UnitaMisuraPesoColli: RawUTF8 index 10 read FUnitaMisuraPesoColli write FUnitaMisuraPesoColli;
property PesoColli: Double read FPesoColli write FPesoColli;
property DataOraRitiro: TTimeLog read FDataOraRitiro write FDataOraRitiro;
property DataInizioTrasporto: TTimeLog read FDataInizioTrasporto write FDataInizioTrasporto;
property IndirizzoConsegna: RawUTF8 read FIndirizzoConsegna write FIndirizzoConsegna;
property NumeroCivicoConsegna: RawUTF8 read FNumeroCivicoConsegna write FNumeroCivicoConsegna;
property CAPConsegna: RawUTF8 read FCAPConsegna write FCAPConsegna;
property ComuneConsegna: RawUTF8 read FComuneConsegna write FComuneConsegna;
property ProvinciaConsegna: RawUTF8 read FProvinciaConsegna write FProvinciaConsegna;
property NazioneConsegna: RawUTF8 read FNazioneConsegna write FNazioneConsegna;
property DataOraConsegna: TTimeLog read FDataOraConsegna write FDataOraConsegna;
property CondizioniPagamento: RawUTF8 index 4 read FCondizioniPagamento write FCondizioniPagamento;
property DettagliPagamento: TDettagliPagamento read FDettagliPagamento write FDettagliPagamento;
property RigheDocumento: TRigheDocumento read FRigheDocumento write FRigheDocumento;
property RiepilogoIVA: TRiepilogoIVA read getRiepilogoIVA;
property Imponibile: Double read getImponibile;
property Imposta: Double read getImposta;
property Totale: Double read getTotale;
end;
and the RiepilogoIVA definition
TDettaglioIVA = record
Aliquota: Double;
Imponibile: Double;
Imposta: Double;
Totale: Double;
end;
TRiepilogoIVA = array of TDettaglioIVA;
and the getRiepilogoIVA implementation detail
function TSQLDocumento.getRiepilogoIVA: TRiepilogoIVA;
var
I, J: Integer;
rIVA: TDynArray;
dIVA: TDettaglioIVA;
begin
setLength(result, 0);
rIVA.Init(TypeInfo(TRiepilogoIVA), result);
//ciclo tutte le righe del documento
for I := 0 to High(self.FRigheDocumento) do
begin
dIVA.Aliquota := self.FRigheDocumento[i].Aliquota;
dIVA.Imponibile := self.FRigheDocumento[i].getImponibile;
dIVA.Imposta := self.FRigheDocumento[i].getImposta;
dIVA.Totale := self.FRigheDocumento[i].getTotale;
//verifico aliquota iva
//se nuova inserisco riga
J := rIVA.FindAndAddIfNotExisting(dIVA, nil, SortDynArrayDouble);
//altrimenti la sommo a quella presente
if (J > -1) then
begin
TDettaglioIVA(rIVA.ElemPtr(J)^).Imponibile := TDettaglioIVA(rIVA.ElemPtr(J)^).Imponibile + self.FRigheDocumento[i].getImponibile;
TDettaglioIVA(rIVA.ElemPtr(J)^).Imposta := TDettaglioIVA(rIVA.ElemPtr(J)^).Imposta + self.FRigheDocumento[i].getImposta;
TDettaglioIVA(rIVA.ElemPtr(J)^).Totale := TDettaglioIVA(rIVA.ElemPtr(J)^).Totale + self.FRigheDocumento[i].getTotale;
end;
end;
end;
Offline
You have no setter for the properties...
So serialization cannot work!
Use plain read and write on a true field, or even better do not include them as published property but as public property.
Offline
it works!!!
thanks ab for the step by step help
another question, you ask me for the sicSingle/sicShared interface service.
In this case i use the service to update other table/tsqlRecord when add/update/delete a TSQLDocumento so i use sicSingle.
What do you think is the best instance implementation for this case?
Offline
I suspect sicShared would be enough, and using a little less resources.
With sicSingle, a TServiceDocumento instance would be created for every request, which is a bit overkill IMHO.
Offline
hi ab,
i'm testing this code
procedure TSQLDocumento.ComputeFieldsBeforeWrite(aRest: TSQLRest;
aOccasion: TSQLEvent);
var I: IServiceDocumento;
begin
inherited;
if aRest.Services['ServiceDocumento'].Get(I) then
begin
case aOccasion of
seAdd: I.EmettiDocumento(self);
seUpdate: I.ModificaDocumento(self);
seDelete: I.AnnullaDocumento(self);
end;
end;
end;
and i see that seDelete Occasion never happen!
when i delete a record seem do not enter in ComputeFieldsBeforeWrite.
how can manage this case?
thanks
Offline
ComputeFieldsBeforeWrite is not called before deletion.
Its purpose is not to be a notification callback, but to modify the fields on the fly - as its name states.
So before a deletion, there is no field to be computed, since the fields would be deleted with the corresponding record/object.
Try to use the TSQLRestServer.OnBeforeURI event instead.
Offline