Improved JSON-RPC support

Improved JSON-RPC sample
This commit is contained in:
Daniele Teti 2017-10-10 12:19:46 +02:00
parent ac654658f1
commit 84ccc385c1
6 changed files with 477 additions and 152 deletions

View File

@ -2,8 +2,8 @@ object Form10: TForm10
Left = 0 Left = 0
Top = 0 Top = 0
Caption = 'Form10' Caption = 'Form10'
ClientHeight = 544 ClientHeight = 448
ClientWidth = 508 ClientWidth = 831
Color = clBtnFace Color = clBtnFace
Font.Charset = DEFAULT_CHARSET Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText Font.Color = clWindowText
@ -11,116 +11,153 @@ object Form10: TForm10
Font.Name = 'Tahoma' Font.Name = 'Tahoma'
Font.Style = [] Font.Style = []
OldCreateOrder = False OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96 PixelsPerInch = 96
TextHeight = 13 TextHeight = 13
object edtValue1: TEdit object GroupBox1: TGroupBox
Left = 8 Left = 8
Top = 8 Top = 16
Width = 89 Width = 815
Height = 124
Caption = 'Simple Types'
TabOrder = 0
object edtValue1: TEdit
Left = 17
Top = 32
Width = 70
Height = 21 Height = 21
TabOrder = 0 TabOrder = 0
Text = '42' Text = '42'
end end
object edtValue2: TEdit object edtValue2: TEdit
Left = 103 Left = 93
Top = 8 Top = 32
Width = 89 Width = 70
Height = 21 Height = 21
TabOrder = 1 TabOrder = 1
Text = '10' Text = '10'
end end
object btnSubstract: TButton object btnSubstract: TButton
Left = 198 Left = 169
Top = 6 Top = 30
Width = 91 Width = 100
Height = 25 Height = 25
Caption = 'Subtract' Caption = 'Subtract'
TabOrder = 2 TabOrder = 2
OnClick = btnSubstractClick OnClick = btnSubstractClick
end end
object edtResult: TEdit object edtResult: TEdit
Left = 295 Left = 273
Top = 8 Top = 32
Width = 74 Width = 70
Height = 21 Height = 21
ReadOnly = True ReadOnly = True
TabOrder = 3 TabOrder = 3
end end
object edtReverseString: TEdit object edtReverseString: TEdit
Left = 8 Left = 17
Top = 56 Top = 80
Width = 184 Width = 144
Height = 21 Height = 21
TabOrder = 4 TabOrder = 4
Text = 'Daniele Teti' Text = 'Daniele Teti'
end end
object btnReverseString: TButton object btnReverseString: TButton
Left = 198 Left = 167
Top = 54 Top = 78
Width = 91 Width = 100
Height = 25 Height = 25
Caption = 'Reverse String' Caption = 'Reverse String'
TabOrder = 5 TabOrder = 5
OnClick = btnReverseStringClick OnClick = btnReverseStringClick
end end
object edtReversedString: TEdit object edtReversedString: TEdit
Left = 295 Left = 273
Top = 56 Top = 80
Width = 202 Width = 178
Height = 21 Height = 21
ReadOnly = True ReadOnly = True
TabOrder = 6 TabOrder = 6
end end
object edtFilter: TEdit object dtNextMonday: TDateTimePicker
Left = 8 Left = 501
Top = 245 Top = 30
Width = 184 Width = 102
Height = 21 Height = 21
Date = 43018.469176562500000000
Time = 43018.469176562500000000
TabOrder = 7 TabOrder = 7
end end
object edtGetCustomers: TButton object btnAddDay: TButton
Left = 198 Left = 609
Top = 243 Top = 30
Width = 91 Width = 128
Height = 25 Height = 25
Caption = 'Get Customers' Caption = 'Get Next Monday'
TabOrder = 8 TabOrder = 8
OnClick = edtGetCustomersClick OnClick = btnAddDayClick
end end
object DBGrid1: TDBGrid object btnInvalid1: TButton
Left = 8 Left = 582
Top = 272 Top = 78
Width = 489 Width = 112
Height = 264 Height = 43
DataSource = DataSource1 Caption = 'Passing VAR parameters'
Font.Charset = DEFAULT_CHARSET
Font.Color = clScrollBar
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
TabOrder = 9 TabOrder = 9
TitleFont.Charset = DEFAULT_CHARSET WordWrap = True
TitleFont.Color = clWindowText OnClick = btnInvalid1Click
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
end end
object edtUserName: TEdit object btnInvalid2: TButton
Left = 700
Top = 78
Width = 112
Height = 43
Caption = 'Passing OUT parameters'
Font.Charset = DEFAULT_CHARSET
Font.Color = clScrollBar
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
TabOrder = 10
WordWrap = True
OnClick = btnInvalid2Click
end
end
object GroupBox2: TGroupBox
Left = 8 Left = 8
Top = 104 Top = 146
Width = 489
Height = 159
Caption = 'Returning Objects'
TabOrder = 1
object edtUserName: TEdit
Left = 16
Top = 24
Width = 184 Width = 184
Height = 21 Height = 21
TabOrder = 10 TabOrder = 0
Text = 'dteti' Text = 'dteti'
end end
object btnGetUser: TButton object btnGetUser: TButton
Left = 198 Left = 206
Top = 102 Top = 22
Width = 91 Width = 91
Height = 25 Height = 25
Caption = 'Get User' Caption = 'Get User'
TabOrder = 11 TabOrder = 1
OnClick = btnGetUserClick OnClick = btnGetUserClick
end end
object lbPerson: TListBox object lbPerson: TListBox
Left = 8 Left = 16
Top = 133 Top = 53
Width = 489 Width = 435
Height = 82 Height = 82
Font.Charset = DEFAULT_CHARSET Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText Font.Color = clWindowText
@ -128,12 +165,108 @@ object Form10: TForm10
Font.Name = 'Courier New' Font.Name = 'Courier New'
Font.Style = [] Font.Style = []
ParentFont = False ParentFont = False
TabOrder = 12 TabOrder = 2
end
end
object GroupBox3: TGroupBox
Left = 509
Top = 146
Width = 314
Height = 294
Caption = 'Returning Datasets'
TabOrder = 2
object edtFilter: TEdit
Left = 18
Top = 32
Width = 184
Height = 21
TabOrder = 0
end
object edtGetCustomers: TButton
Left = 208
Top = 30
Width = 91
Height = 25
Caption = 'Get Customers'
TabOrder = 1
OnClick = edtGetCustomersClick
end
object DBGrid1: TDBGrid
Left = 18
Top = 61
Width = 279
Height = 204
DataSource = DataSource1
TabOrder = 2
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
end
end
object GroupBox4: TGroupBox
Left = 8
Top = 311
Width = 489
Height = 129
Caption = 'Passing Objects as parameters'
TabOrder = 3
object edtFirstName: TLabeledEdit
Left = 16
Top = 40
Width = 121
Height = 21
EditLabel.Width = 51
EditLabel.Height = 13
EditLabel.Caption = 'First Name'
TabOrder = 0
Text = 'Daniele'
end
object edtLastName: TLabeledEdit
Left = 16
Top = 88
Width = 121
Height = 21
EditLabel.Width = 50
EditLabel.Height = 13
EditLabel.Caption = 'Last Name'
TabOrder = 1
Text = 'Teti'
end
object chkMarried: TCheckBox
Left = 172
Top = 40
Width = 97
Height = 17
Caption = 'Married'
Checked = True
State = cbChecked
TabOrder = 2
end
object dtDOB: TDateTimePicker
Left = 169
Top = 88
Width = 102
Height = 21
Date = 29163.469176562500000000
Time = 29163.469176562500000000
TabOrder = 3
end
object btnSave: TButton
Left = 376
Top = 88
Width = 75
Height = 25
Caption = 'Save'
TabOrder = 4
OnClick = btnSaveClick
end
end end
object DataSource1: TDataSource object DataSource1: TDataSource
DataSet = FDMemTable1 DataSet = FDMemTable1
Left = 256 Left = 767
Top = 280 Top = 184
end end
object FDMemTable1: TFDMemTable object FDMemTable1: TFDMemTable
FetchOptions.AssignedValues = [evMode] FetchOptions.AssignedValues = [evMode]
@ -143,8 +276,8 @@ object Form10: TForm10
UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates] UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
UpdateOptions.CheckRequired = False UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True UpdateOptions.AutoCommitUpdates = True
Left = 256 Left = 767
Top = 344 Top = 248
object FDMemTable1Code: TIntegerField object FDMemTable1Code: TIntegerField
FieldName = 'Code' FieldName = 'Code'
end end

View File

@ -8,10 +8,15 @@ uses
System.Net.URLClient, System.Net.HttpClient, Data.DB, Vcl.Grids, Vcl.DBGrids, System.Net.URLClient, System.Net.HttpClient, Data.DB, Vcl.Grids, Vcl.DBGrids,
FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
FireDAC.Comp.DataSet, FireDAC.Comp.Client; FireDAC.Comp.DataSet, FireDAC.Comp.Client, Vcl.ComCtrls, Vcl.ExtCtrls;
type type
TForm10 = class(TForm) TForm10 = class(TForm)
DataSource1: TDataSource;
FDMemTable1: TFDMemTable;
FDMemTable1Code: TIntegerField;
FDMemTable1Name: TStringField;
GroupBox1: TGroupBox;
edtValue1: TEdit; edtValue1: TEdit;
edtValue2: TEdit; edtValue2: TEdit;
btnSubstract: TButton; btnSubstract: TButton;
@ -19,20 +24,33 @@ type
edtReverseString: TEdit; edtReverseString: TEdit;
btnReverseString: TButton; btnReverseString: TButton;
edtReversedString: TEdit; edtReversedString: TEdit;
edtFilter: TEdit; GroupBox2: TGroupBox;
edtGetCustomers: TButton;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
FDMemTable1: TFDMemTable;
FDMemTable1Code: TIntegerField;
FDMemTable1Name: TStringField;
edtUserName: TEdit; edtUserName: TEdit;
btnGetUser: TButton; btnGetUser: TButton;
lbPerson: TListBox; lbPerson: TListBox;
GroupBox3: TGroupBox;
edtFilter: TEdit;
edtGetCustomers: TButton;
DBGrid1: TDBGrid;
GroupBox4: TGroupBox;
edtFirstName: TLabeledEdit;
edtLastName: TLabeledEdit;
chkMarried: TCheckBox;
dtDOB: TDateTimePicker;
btnSave: TButton;
dtNextMonday: TDateTimePicker;
btnAddDay: TButton;
btnInvalid1: TButton;
btnInvalid2: TButton;
procedure btnSubstractClick(Sender: TObject); procedure btnSubstractClick(Sender: TObject);
procedure btnReverseStringClick(Sender: TObject); procedure btnReverseStringClick(Sender: TObject);
procedure edtGetCustomersClick(Sender: TObject); procedure edtGetCustomersClick(Sender: TObject);
procedure btnGetUserClick(Sender: TObject); procedure btnGetUserClick(Sender: TObject);
procedure btnSaveClick(Sender: TObject);
procedure btnAddDayClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnInvalid1Click(Sender: TObject);
procedure btnInvalid2Click(Sender: TObject);
private private
{ Private declarations } { Private declarations }
public public
@ -46,7 +64,8 @@ implementation
uses uses
MVCFramework.JSONRPC, MVCFramework.Serializer.JsonDataObjects, MVCFramework.JSONRPC, MVCFramework.Serializer.JsonDataObjects,
JsonDataObjects, MVCFramework.Serializer.Commons, MVCFramework.DataSet.Utils; JsonDataObjects, MVCFramework.Serializer.Commons, MVCFramework.DataSet.Utils,
BusinessObjectsU;
{$R *.dfm} {$R *.dfm}
@ -86,6 +105,27 @@ begin
end; end;
end; end;
procedure TForm10.btnAddDayClick(Sender: TObject);
var
lReq: TJSONRPCRequest;
lResp: TJSONRPCResponse;
begin
lReq := TJSONRPCRequest.Create;
try
lReq.Method := 'getnextmonday';
lReq.RequestID := Random(1000);
lReq.Params.Add(dtNextMonday.Date);
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try
dtNextMonday.Date := ISOTimeStampToDateTime(lResp.Result.AsString);
finally
lResp.Free;
end;
finally
lReq.Free;
end;
end;
procedure TForm10.btnGetUserClick(Sender: TObject); procedure TForm10.btnGetUserClick(Sender: TObject);
var var
lReq: TJSONRPCRequest; lReq: TJSONRPCRequest;
@ -96,7 +136,7 @@ begin
lReq := TJSONRPCRequest.Create; lReq := TJSONRPCRequest.Create;
try try
lReq.Method := 'getuser'; lReq.Method := 'getuser';
lReq.ID := Random(1000); lReq.RequestID := Random(1000);
lReq.Params.Add(edtUserName.Text); lReq.Params.Add(edtUserName.Text);
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp); JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try try
@ -118,6 +158,47 @@ begin
end; end;
end; end;
procedure TForm10.btnInvalid1Click(Sender: TObject);
var
lReq: TJSONRPCRequest;
lResp: TJSONRPCResponse;
begin
lReq := TJSONRPCRequest.Create;
try
lReq.Method := 'invalidmethod1';
lReq.Params.Add(1);
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try
ShowMessage(lResp.Error.ErrMessage);
finally
lResp.Free;
end;
finally
lReq.Free;
end;
end;
procedure TForm10.btnInvalid2Click(Sender: TObject);
var
lReq: TJSONRPCRequest;
lResp: TJSONRPCResponse;
begin
lReq := TJSONRPCRequest.Create;
try
lReq.Method := 'invalidmethod2';
lReq.Params.Add(1);
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try
ShowMessage(lResp.Error.ErrMessage);
finally
lResp.Free;
end;
finally
lReq.Free;
end;
end;
procedure TForm10.btnReverseStringClick(Sender: TObject); procedure TForm10.btnReverseStringClick(Sender: TObject);
var var
lReq: TJSONRPCRequest; lReq: TJSONRPCRequest;
@ -126,7 +207,7 @@ begin
lReq := TJSONRPCRequest.Create; lReq := TJSONRPCRequest.Create;
try try
lReq.Method := 'reversestring'; lReq.Method := 'reversestring';
lReq.ID := Random(1000); lReq.RequestID := Random(1000);
lReq.Params.Add(edtReverseString.Text); lReq.Params.Add(edtReverseString.Text);
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp); JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try try
@ -139,6 +220,33 @@ begin
end; end;
end; end;
procedure TForm10.btnSaveClick(Sender: TObject);
var
lPerson: TPerson;
lReq: TJSONRPCRequest;
lResp: TJSONRPCResponse;
begin
lReq := TJSONRPCRequest.Create;
try
lReq.Method := 'saveperson';
lReq.RequestID := Random(1000);
lPerson := TPerson.Create;
lReq.Params.Add(lperson);
lPerson.FirstName := edtFirstName.Text;
lPerson.LastName := edtLastName.Text;
lPerson.Married := chkMarried.Checked;
lPerson.DOB := dtDOB.Date;
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try
ShowMessage('Person saved with ID = ' + lResp.Result.AsInteger.ToString);
finally
lResp.Free;
end;
finally
lReq.Free;
end;
end;
procedure TForm10.btnSubstractClick(Sender: TObject); procedure TForm10.btnSubstractClick(Sender: TObject);
var var
lReq: TJSONRPCRequest; lReq: TJSONRPCRequest;
@ -147,7 +255,7 @@ begin
lReq := TJSONRPCRequest.Create; lReq := TJSONRPCRequest.Create;
try try
lReq.Method := 'subtract'; lReq.Method := 'subtract';
lReq.ID := Random(1000); lReq.RequestID := Random(1000);
lReq.Params.Add(StrToInt(edtValue1.Text)); lReq.Params.Add(StrToInt(edtValue1.Text));
lReq.Params.Add(StrToInt(edtValue2.Text)); lReq.Params.Add(StrToInt(edtValue2.Text));
@ -171,7 +279,7 @@ begin
lReq := TJSONRPCRequest.Create; lReq := TJSONRPCRequest.Create;
try try
lReq.Method := 'getcustomers'; lReq.Method := 'getcustomers';
lReq.ID := Random(1000); lReq.RequestID := Random(1000);
lReq.Params.Add(edtFilter.Text); lReq.Params.Add(edtFilter.Text);
JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp); JSONRPCExec('http://localhost:8080/jsonrpc', lReq, lResp);
try try
@ -185,4 +293,9 @@ begin
end; end;
end; end;
procedure TForm10.FormCreate(Sender: TObject);
begin
dtNextMonday.Date := Date;
end;
end. end.

View File

@ -11,16 +11,21 @@ type
public public
function Subtract(aValue1, aValue2: Integer): Integer; function Subtract(aValue1, aValue2: Integer): Integer;
function ReverseString(aString: string): string; function ReverseString(aString: string): string;
function GetNextMonday(const aDate: TDate): TDate;
function GetCustomers(aString: string): TDataSet; function GetCustomers(aString: string): TDataSet;
function GetUser(aUserName: string): TPerson; function GetUser(aUserName: string): TPerson;
function SavePerson(const aPerson: TJsonObject): Integer;
procedure DoSomething; procedure DoSomething;
// invalid parameters modifiers
procedure InvalidMethod1(var MyVarParam: Integer);
procedure InvalidMethod2(out MyOutParam: Integer);
end; end;
implementation implementation
uses uses
System.SysUtils, MVCFramework.Logger, System.StrUtils, FireDAC.Comp.Client; System.SysUtils, MVCFramework.Logger, System.StrUtils, FireDAC.Comp.Client, System.DateUtils;
{ TMyDerivedController } { TMyDerivedController }
@ -66,6 +71,18 @@ begin
end; end;
end; end;
function TMyJSONRPCController.GetNextMonday(const aDate: TDate): TDate;
var
lDate: TDate;
begin
lDate := aDate + 1;
while DayOfTheWeek(lDate) <> 1 do
begin
lDate := lDate + 1;
end;
Result := lDate;
end;
function TMyJSONRPCController.GetUser(aUserName: string): TPerson; function TMyJSONRPCController.GetUser(aUserName: string): TPerson;
begin begin
Result := TPerson.Create; Result := TPerson.Create;
@ -75,11 +92,36 @@ begin
Result.Married := True; Result.Married := True;
end; end;
procedure TMyJSONRPCController.InvalidMethod1(var MyVarParam: Integer);
begin
// do nothing
end;
procedure TMyJSONRPCController.InvalidMethod2(out MyOutParam: Integer);
begin
// do nothing
end;
function TMyJSONRPCController.ReverseString(aString: string): string; function TMyJSONRPCController.ReverseString(aString: string): string;
begin begin
Result := System.StrUtils.ReverseString(aString); Result := System.StrUtils.ReverseString(aString);
end; end;
function TMyJSONRPCController.SavePerson(const aPerson: TJsonObject): Integer;
var
lPerson: TPerson;
begin
lPerson := JSONObjectAs<TPerson>(aPerson);
try
// do something with lPerson
finally
lPerson.Free;
end;
// this maybe the id of the newly created person
Result := Random(1000);
end;
function TMyJSONRPCController.Subtract(aValue1, aValue2: Integer): Integer; function TMyJSONRPCController.Subtract(aValue1, aValue2: Integer): Integer;
begin begin
Result := aValue1 - aValue2; Result := aValue1 - aValue2;

View File

@ -2,7 +2,8 @@ program jsonrpcclient;
uses uses
Vcl.Forms, Vcl.Forms,
MainClientFormU in 'MainClientFormU.pas' {Form10}; MainClientFormU in 'MainClientFormU.pas' {Form10},
BusinessObjectsU in '..\commons\BusinessObjectsU.pas';
{$R *.res} {$R *.res}

View File

@ -103,6 +103,7 @@
<Form>Form10</Form> <Form>Form10</Form>
<FormType>dfm</FormType> <FormType>dfm</FormType>
</DCCReference> </DCCReference>
<DCCReference Include="..\commons\BusinessObjectsU.pas"/>
<BuildConfiguration Include="Release"> <BuildConfiguration Include="Release">
<Key>Cfg_2</Key> <Key>Cfg_2</Key>
<CfgParent>Base</CfgParent> <CfgParent>Base</CfgParent>

View File

@ -5,7 +5,8 @@ interface
uses uses
System.Classes, Data.DB, System.SysUtils, System.Classes, Data.DB, System.SysUtils,
jsondataobjects, MVCFramework, MVCFramework.Commons, System.Rtti, jsondataobjects, MVCFramework, MVCFramework.Commons, System.Rtti,
System.Generics.Collections, MVCFramework.Serializer.Commons; System.Generics.Collections, MVCFramework.Serializer.Commons,
MVCFramework.Serializer.JsonDataObjects;
const const
JSONRPC_VERSION = '2.0'; JSONRPC_VERSION = '2.0';
@ -53,7 +54,7 @@ type
constructor Create; virtual; constructor Create; virtual;
property AsJSON: TJsonObject read GetJSON write SetJSON; property AsJSON: TJsonObject read GetJSON write SetJSON;
property AsJSONString: string read GetJSONString write SetJsonString; property AsJSONString: string read GetJSONString write SetJsonString;
property ID: TValue read FID write SetID; property RequestID: TValue read FID write SetID;
end; end;
{$SCOPEDENUMS ON} {$SCOPEDENUMS ON}
@ -158,23 +159,28 @@ type
TMVCJSONArray = TJDOJsonArray; TMVCJSONArray = TJDOJsonArray;
TMVCJSONRPCController = class(TMVCController) TMVCJSONRPCController = class(TMVCController)
private
fSerializer: TMVCJsonDataObjectsSerializer;
function GetSerializer: TMVCJsonDataObjectsSerializer;
protected protected
function CreateError(const RequestID: TValue; const ErrorCode: Integer; function CreateError(const RequestID: TValue; const ErrorCode: Integer;
const message: string): TJsonObject; const message: string): TJsonObject;
function CreateResponse(const RequestID: TValue; const Value: TValue): TJSONRPCResponse; function CreateResponse(const RequestID: TValue; const Value: TValue): TJSONRPCResponse;
function CreateRequest(const JSON: TJsonObject): TJSONRPCRequest; function CreateRequest(const JSON: TJsonObject): TJSONRPCRequest;
function JSONObjectAs<T: class, constructor>(const JSON: TJsonObject): T;
public public
[MVCPath] [MVCPath]
[MVCHTTPMethods([httpPOST])] [MVCHTTPMethods([httpPOST])]
[MVCConsumes(TMVCMediaType.APPLICATION_JSON)] [MVCConsumes(TMVCMediaType.APPLICATION_JSON)]
[MVCProduces(TMVCMediaType.APPLICATION_JSON)] [MVCProduces(TMVCMediaType.APPLICATION_JSON)]
procedure index; virtual; procedure index; virtual;
destructor Destroy; override;
end; end;
implementation implementation
uses uses
MVCFramework.Serializer.Intf, MVCFramework.Serializer.JsonDataObjects; MVCFramework.Serializer.Intf, System.TypInfo;
function JSONDataValueToTValue(const JSONDataValue: TJsonDataValueHelper): TValue; function JSONDataValueToTValue(const JSONDataValue: TJsonDataValueHelper): TValue;
begin begin
@ -419,7 +425,7 @@ var
begin begin
lErrResp := TJSONRPCResponse.Create; lErrResp := TJSONRPCResponse.Create;
try try
lErrResp.ID := RequestID; lErrResp.RequestID := RequestID;
lErrResp.Error := TJSONRPCResponse.TJSONRPCResponseError.Create; lErrResp.Error := TJSONRPCResponse.TJSONRPCResponseError.Create;
lErrResp.Error.Code := ErrorCode; lErrResp.Error.Code := ErrorCode;
lErrResp.Error.ErrMessage := message; lErrResp.Error.ErrMessage := message;
@ -438,15 +444,15 @@ begin
try try
Result := TJSONRPCRequest.Create; Result := TJSONRPCRequest.Create;
if JSON.Types[JSONRPC_ID] = jdtString then if JSON.Types[JSONRPC_ID] = jdtString then
Result.ID := JSON.S[JSONRPC_ID] Result.RequestID := JSON.S[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtInt then else if JSON.Types[JSONRPC_ID] = jdtInt then
Result.ID := JSON.I[JSONRPC_ID] Result.RequestID := JSON.I[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtLong then else if JSON.Types[JSONRPC_ID] = jdtLong then
Result.ID := JSON.L[JSONRPC_ID] Result.RequestID := JSON.L[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtULong then else if JSON.Types[JSONRPC_ID] = jdtULong then
Result.ID := JSON.U[JSONRPC_ID] Result.RequestID := JSON.U[JSONRPC_ID]
else else
Result.ID := TValue.Empty; Result.RequestID := TValue.Empty;
Result.Method := JSON.S[JSONRPC_METHOD]; Result.Method := JSON.S[JSONRPC_METHOD];
@ -470,10 +476,23 @@ end;
function TMVCJSONRPCController.CreateResponse(const RequestID: TValue; const Value: TValue): TJSONRPCResponse; function TMVCJSONRPCController.CreateResponse(const RequestID: TValue; const Value: TValue): TJSONRPCResponse;
begin begin
Result := TJSONRPCResponse.Create; Result := TJSONRPCResponse.Create;
Result.ID := RequestID; Result.RequestID := RequestID;
Result.Result := Value; Result.Result := Value;
end; end;
destructor TMVCJSONRPCController.Destroy;
begin
fSerializer.Free;
inherited;
end;
function TMVCJSONRPCController.GetSerializer: TMVCJsonDataObjectsSerializer;
begin
if not Assigned(fSerializer) then
fSerializer := TMVCJsonDataObjectsSerializer.Create;
Result := fSerializer;
end;
procedure TMVCJSONRPCController.Index; procedure TMVCJSONRPCController.Index;
var var
lJSONRPCReq: TJSONRPCRequest; lJSONRPCReq: TJSONRPCRequest;
@ -486,6 +505,7 @@ var
lJSONRPCResponse: TJSONRPCResponse; lJSONRPCResponse: TJSONRPCResponse;
lParamsToInject: TArray<TValue>; lParamsToInject: TArray<TValue>;
lReqID: TValue; lReqID: TValue;
lRTTIMethodParam: TRttiParameter;
begin begin
lReqID := TValue.Empty; lReqID := TValue.Empty;
SetLength(lParamsToInject, 0); SetLength(lParamsToInject, 0);
@ -503,6 +523,12 @@ begin
if (Length(lRTTIMethodParams) <> lJSONRPCReq.Params.Count) then if (Length(lRTTIMethodParams) <> lJSONRPCReq.Params.Count) then
raise EMVCJSONRPCInvalidParams.Create('Wrong parameters count'); raise EMVCJSONRPCInvalidParams.Create('Wrong parameters count');
for lRTTIMethodParam in lRTTIMethodParams do
begin
if lRTTIMethodParam.Flags * [pfVar, pfOut, pfArray, pfReference] <> [] then
raise EMVCJSONRPCInvalidParams.CreateFmt('Parameter modifier not supported for formal parameter [%s]. Only const and value modifiers are allowed.', [lRTTIMethodParam.Name])
end;
try try
try try
lRes := lRTTIMethod.Invoke(Self, lJSONRPCReq.Params.ToArray); lRes := lRTTIMethod.Invoke(Self, lJSONRPCReq.Params.ToArray);
@ -520,7 +546,7 @@ begin
end end
else else
begin begin
lJSONRPCResponse := CreateResponse(lJSONRPCReq.ID, lRes); lJSONRPCResponse := CreateResponse(lJSONRPCReq.RequestID, lRes);
try try
ResponseStatus(200); ResponseStatus(200);
Render(lJSONRPCResponse.AsJSON); Render(lJSONRPCResponse.AsJSON);
@ -571,6 +597,17 @@ begin
end; end;
end; end;
function TMVCJSONRPCController.JSONObjectAs<T>(const JSON: TJsonObject): T;
begin
Result := T.Create;
try
GetSerializer.JsonObjectToObject(JSON, Result, TMVCSerializationType.stProperties, []);
except
Result.Free;
raise;
end;
end;
{ EMVCJSONRPCParseError } { EMVCJSONRPCParseError }
constructor EMVCJSONRPCParseError.Create; constructor EMVCJSONRPCParseError.Create;
@ -620,8 +657,6 @@ begin
end; end;
{ TMVCJSONRCPResponse }
{ TJSONRPCRequest } { TJSONRPCRequest }
constructor TJSONRPCRequest.Create; constructor TJSONRPCRequest.Create;
@ -674,15 +709,15 @@ var
lParams: TJsonArray; lParams: TJsonArray;
begin begin
if JSON.Types[JSONRPC_ID] = jdtString then if JSON.Types[JSONRPC_ID] = jdtString then
ID := JSON.S[JSONRPC_ID] RequestID := JSON.S[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtInt then else if JSON.Types[JSONRPC_ID] = jdtInt then
ID := JSON.I[JSONRPC_ID] RequestID := JSON.I[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtLong then else if JSON.Types[JSONRPC_ID] = jdtLong then
ID := JSON.L[JSONRPC_ID] RequestID := JSON.L[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtULong then else if JSON.Types[JSONRPC_ID] = jdtULong then
ID := JSON.U[JSONRPC_ID] RequestID := JSON.U[JSONRPC_ID]
else else
ID := TValue.Empty; RequestID := TValue.Empty;
Method := JSON.S[JSONRPC_METHOD]; Method := JSON.S[JSONRPC_METHOD];
Params.Clear; Params.Clear;
@ -750,15 +785,15 @@ end;
procedure TJSONRPCResponse.SetJSON(const JSON: TJsonObject); procedure TJSONRPCResponse.SetJSON(const JSON: TJsonObject);
begin begin
if JSON.Types[JSONRPC_ID] = jdtString then if JSON.Types[JSONRPC_ID] = jdtString then
ID := JSON.S[JSONRPC_ID] RequestID := JSON.S[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtInt then else if JSON.Types[JSONRPC_ID] = jdtInt then
ID := JSON.I[JSONRPC_ID] RequestID := JSON.I[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtLong then else if JSON.Types[JSONRPC_ID] = jdtLong then
ID := JSON.L[JSONRPC_ID] RequestID := JSON.L[JSONRPC_ID]
else if JSON.Types[JSONRPC_ID] = jdtULong then else if JSON.Types[JSONRPC_ID] = jdtULong then
ID := JSON.U[JSONRPC_ID] RequestID := JSON.U[JSONRPC_ID]
else else
ID := TValue.Empty; RequestID := TValue.Empty;
if JSON.Contains(JSONRPC_RESULT) then if JSON.Contains(JSONRPC_RESULT) then
begin begin