diff --git a/samples/_/Image00001.jpg b/samples/_/Image00001.jpg new file mode 100644 index 00000000..f7bbcc90 Binary files /dev/null and b/samples/_/Image00001.jpg differ diff --git a/samples/_/Image00002.jpg b/samples/_/Image00002.jpg new file mode 100644 index 00000000..16a8d429 Binary files /dev/null and b/samples/_/Image00002.jpg differ diff --git a/samples/_/Image00003.jpg b/samples/_/Image00003.jpg new file mode 100644 index 00000000..86cbf344 Binary files /dev/null and b/samples/_/Image00003.jpg differ diff --git a/samples/functional_actions_showcase/ControllerU.pas b/samples/functional_actions_showcase/ControllerU.pas index 9cb132b5..94f89405 100644 --- a/samples/functional_actions_showcase/ControllerU.pas +++ b/samples/functional_actions_showcase/ControllerU.pas @@ -4,7 +4,8 @@ interface uses MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons, - System.Generics.Collections, Data.DB, JsonDataObjects, System.Rtti; + System.Generics.Collections, Data.DB, JsonDataObjects, System.Rtti, + System.Classes; type TPersonRec = record @@ -43,11 +44,15 @@ type [MVCPath('/records/multiple')] function GetMultipleRecords: TArray; - { actions returning objects } + { actions returning objects and binary data} [MVCPath('/objects/single')] function GetSingleObject: TPerson; [MVCPath('/objects/multiple')] function GetMultipleObjects: TObjectList; + [MVCPath('/files/customers/($ID)')] + function GetCustomerPhoto(const ID: Integer): TStream; + [MVCPath('/files/sea/($ID)')] + function GetSeaPhoto(const ID: Integer): TStream; { actions returning json } [MVCPath('/objects/jsonobject')] @@ -107,10 +112,27 @@ implementation uses System.SysUtils, MVCFramework.Logger, System.StrUtils, System.DateUtils, - MainDMU, FireDAC.Comp.Client, MVCFramework.FireDAC.Utils; + MainDMU, FireDAC.Comp.Client, MVCFramework.FireDAC.Utils, System.IOUtils; { TMyController } +function TMyController.GetSeaPhoto(const ID: Integer): TStream; +var + lBasePath: String; +begin + lBasePath := TPath.Combine(TPath.Combine(AppPath, '..', '..','..'), '_', 'Image%.5d.jpg'); + lBasePath := Format(lBasePath, [ID]); + if not TFile.Exists(lBasePath) then + begin + raise EMVCException.Create(HTTP_STATUS.NotFound, 'File not found'); + end + else + begin + ContentType := TMVCMediaType.IMAGE_PNG; + Result := TFileStream.Create(lBasePath, fmOpenRead or fmShareDenyWrite); + end; +end; + function TMyController.GetSingleDataSet: TDataSet; begin var lDM := TdmMain.Create(nil); @@ -309,6 +331,12 @@ begin Result := A + B; end; +function TMyController.GetCustomerPhoto(const ID: Integer): TStream; +begin + ContentType := TMVCMediaType.IMAGE_PNG; // you can also use MVCProduces attribute + Result := TFileStream.Create('..\..\..\_\customer.png', fmOpenRead or fmShareDenyWrite); +end; + function TMyController.GetGeneralException: Integer; begin raise Exception.Create('This is a general exception'); diff --git a/samples/htmx_website/ControllerU.pas b/samples/htmx_website_with_templatepro/ControllerU.pas similarity index 100% rename from samples/htmx_website/ControllerU.pas rename to samples/htmx_website_with_templatepro/ControllerU.pas diff --git a/samples/htmx_website/HelpersU.pas b/samples/htmx_website_with_templatepro/HelpersU.pas similarity index 100% rename from samples/htmx_website/HelpersU.pas rename to samples/htmx_website_with_templatepro/HelpersU.pas diff --git a/samples/htmx_website/WebModuleU.dfm b/samples/htmx_website_with_templatepro/WebModuleU.dfm similarity index 100% rename from samples/htmx_website/WebModuleU.dfm rename to samples/htmx_website_with_templatepro/WebModuleU.dfm diff --git a/samples/htmx_website/WebModuleU.pas b/samples/htmx_website_with_templatepro/WebModuleU.pas similarity index 100% rename from samples/htmx_website/WebModuleU.pas rename to samples/htmx_website_with_templatepro/WebModuleU.pas diff --git a/samples/htmx_website/bin/templates/baselayout.html b/samples/htmx_website_with_templatepro/bin/templates/baselayout.html similarity index 100% rename from samples/htmx_website/bin/templates/baselayout.html rename to samples/htmx_website_with_templatepro/bin/templates/baselayout.html diff --git a/samples/htmx_website/bin/templates/pages/customers.html b/samples/htmx_website_with_templatepro/bin/templates/pages/customers.html similarity index 100% rename from samples/htmx_website/bin/templates/pages/customers.html rename to samples/htmx_website_with_templatepro/bin/templates/pages/customers.html diff --git a/samples/htmx_website/bin/templates/pages/home.html b/samples/htmx_website_with_templatepro/bin/templates/pages/home.html similarity index 100% rename from samples/htmx_website/bin/templates/pages/home.html rename to samples/htmx_website_with_templatepro/bin/templates/pages/home.html diff --git a/samples/htmx_website/bin/templates/pages/posts.html b/samples/htmx_website_with_templatepro/bin/templates/pages/posts.html similarity index 100% rename from samples/htmx_website/bin/templates/pages/posts.html rename to samples/htmx_website_with_templatepro/bin/templates/pages/posts.html diff --git a/samples/htmx_website/bin/templates/pages/users.html b/samples/htmx_website_with_templatepro/bin/templates/pages/users.html similarity index 100% rename from samples/htmx_website/bin/templates/pages/users.html rename to samples/htmx_website_with_templatepro/bin/templates/pages/users.html diff --git a/samples/htmx_website/bin/templates/partials/sidenav.html b/samples/htmx_website_with_templatepro/bin/templates/partials/sidenav.html similarity index 100% rename from samples/htmx_website/bin/templates/partials/sidenav.html rename to samples/htmx_website_with_templatepro/bin/templates/partials/sidenav.html diff --git a/samples/htmx_website/htmx_website.dpr b/samples/htmx_website_with_templatepro/htmx_website.dpr similarity index 100% rename from samples/htmx_website/htmx_website.dpr rename to samples/htmx_website_with_templatepro/htmx_website.dpr diff --git a/samples/htmx_website/htmx_website.dproj b/samples/htmx_website_with_templatepro/htmx_website.dproj similarity index 100% rename from samples/htmx_website/htmx_website.dproj rename to samples/htmx_website_with_templatepro/htmx_website.dproj diff --git a/samples/instant_search_with_htmx/BooksSearch.dpr b/samples/instant_search_with_htmx_and_templatepro/BooksSearch.dpr similarity index 100% rename from samples/instant_search_with_htmx/BooksSearch.dpr rename to samples/instant_search_with_htmx_and_templatepro/BooksSearch.dpr diff --git a/samples/instant_search_with_htmx/BooksSearch.dproj b/samples/instant_search_with_htmx_and_templatepro/BooksSearch.dproj similarity index 100% rename from samples/instant_search_with_htmx/BooksSearch.dproj rename to samples/instant_search_with_htmx_and_templatepro/BooksSearch.dproj diff --git a/samples/instant_search_with_htmx/Controllers.BooksU.pas b/samples/instant_search_with_htmx_and_templatepro/Controllers.BooksU.pas similarity index 100% rename from samples/instant_search_with_htmx/Controllers.BooksU.pas rename to samples/instant_search_with_htmx_and_templatepro/Controllers.BooksU.pas diff --git a/samples/instant_search_with_htmx/FDConnectionConfigU.pas b/samples/instant_search_with_htmx_and_templatepro/FDConnectionConfigU.pas similarity index 100% rename from samples/instant_search_with_htmx/FDConnectionConfigU.pas rename to samples/instant_search_with_htmx_and_templatepro/FDConnectionConfigU.pas diff --git a/samples/instant_search_with_htmx/WebModuleU.dfm b/samples/instant_search_with_htmx_and_templatepro/WebModuleU.dfm similarity index 100% rename from samples/instant_search_with_htmx/WebModuleU.dfm rename to samples/instant_search_with_htmx_and_templatepro/WebModuleU.dfm diff --git a/samples/instant_search_with_htmx/WebModuleU.pas b/samples/instant_search_with_htmx_and_templatepro/WebModuleU.pas similarity index 100% rename from samples/instant_search_with_htmx/WebModuleU.pas rename to samples/instant_search_with_htmx_and_templatepro/WebModuleU.pas diff --git a/samples/instant_search_with_htmx/bin/templates/baselayout.html b/samples/instant_search_with_htmx_and_templatepro/bin/templates/baselayout.html similarity index 100% rename from samples/instant_search_with_htmx/bin/templates/baselayout.html rename to samples/instant_search_with_htmx_and_templatepro/bin/templates/baselayout.html diff --git a/samples/instant_search_with_htmx/bin/templates/index.html b/samples/instant_search_with_htmx_and_templatepro/bin/templates/index.html similarity index 100% rename from samples/instant_search_with_htmx/bin/templates/index.html rename to samples/instant_search_with_htmx_and_templatepro/bin/templates/index.html diff --git a/samples/instant_search_with_htmx/bin/templates/search_results.html b/samples/instant_search_with_htmx_and_templatepro/bin/templates/search_results.html similarity index 100% rename from samples/instant_search_with_htmx/bin/templates/search_results.html rename to samples/instant_search_with_htmx_and_templatepro/bin/templates/search_results.html diff --git a/samples/jsonrpc/jsonrpcserver/MyObjectU.pas b/samples/jsonrpc/jsonrpcserver/MyObjectU.pas index bb0f9cc2..817955bb 100644 --- a/samples/jsonrpc/jsonrpcserver/MyObjectU.pas +++ b/samples/jsonrpc/jsonrpcserver/MyObjectU.pas @@ -44,8 +44,8 @@ type // function GetPeopleDataset: TFDMemTable; procedure FillPeopleDataset(const DataSet: TDataSet); public - procedure OnBeforeCallHook(const Context: TWebContext; const JSONRequest: TJDOJsonObject); procedure OnBeforeRoutingHook(const Context: TWebContext; const JSON: TJDOJsonObject); + procedure OnBeforeCallHook(const Context: TWebContext; const JSONRequest: TJDOJsonObject); procedure OnAfterCallHook(const Context: TWebContext; const JSONResponse: TJDOJsonObject); public [MVCDoc('You know, returns aValue1 - aValue2')] diff --git a/samples/renders/CustomTypesSerializersU.pas b/samples/renders/CustomTypesSerializersU.pas index 1da2d76c..22182ce0 100644 --- a/samples/renders/CustomTypesSerializersU.pas +++ b/samples/renders/CustomTypesSerializersU.pas @@ -52,6 +52,21 @@ type const AAttributes: System.TArray); end; + // Custom serializer for TSysUserSerializer type + TSysUserSerializer = class(TInterfacedObject, IMVCTypeSerializer) + public + procedure SerializeAttribute(const AElementValue: TValue; const APropertyName: string; + const ASerializerObject: TObject; const AAttributes: System.TArray); + procedure SerializeRoot(const AObject: TObject; out ASerializerObject: TObject; + const AAttributes: System.TArray; + const ASerializationAction: TMVCSerializationAction = nil); + procedure DeserializeAttribute(var AElementValue: TValue; const APropertyName: string; + const ASerializerObject: TObject; const AAttributes: System.TArray); + procedure DeserializeRoot(const ASerializerObject: TObject; const AObject: TObject; + const AAttributes: System.TArray); + end; + + // Custom serializer for TNullableAliasSerializer type TNullableAliasSerializer = class(TInterfacedObject, IMVCTypeSerializer) public @@ -170,4 +185,34 @@ begin raise EMVCSerializationException.CreateFmt('%s cannot be used as root object', [ClassName]); end; +{ TSysUserSerializer } + +procedure TSysUserSerializer.DeserializeAttribute(var AElementValue: TValue; const APropertyName: string; + const ASerializerObject: TObject; const AAttributes: System.TArray); +begin + +end; + +procedure TSysUserSerializer.DeserializeRoot(const ASerializerObject, AObject: TObject; + const AAttributes: System.TArray); +begin + +end; + +procedure TSysUserSerializer.SerializeAttribute(const AElementValue: TValue; const APropertyName: string; + const ASerializerObject: TObject; const AAttributes: System.TArray); +begin + (ASerializerObject as TJDOJsonObject).S['prop'] := 'hello there attribute'; +end; + +procedure TSysUserSerializer.SerializeRoot(const AObject: TObject; out ASerializerObject: TObject; + const AAttributes: System.TArray; const ASerializationAction: TMVCSerializationAction); +var + lJObj: TJDOJsonObject; +begin + lJObj := (ASerializerObject as TJDOJsonObject); + lJObj.S['username'] := TSysUser(AObject).UserName; + lJObj.S['roles'] := String.Join(',', TSysUser(AObject).Roles); +end; + end. diff --git a/samples/renders/CustomTypesU.pas b/samples/renders/CustomTypesU.pas index 9c36936a..fc9e56aa 100644 --- a/samples/renders/CustomTypesU.pas +++ b/samples/renders/CustomTypesU.pas @@ -48,8 +48,8 @@ type // custom serialized type as property Roles TSysUser = class private - FUserName: string; - FRoles: TUserRoles; + fUserName: string; + fRoles: TUserRoles; fRecordAlias: TNullableRecordAlias; procedure SetUserName(const Value: string); function GetUserRoles: TUserRoles; @@ -61,6 +61,19 @@ type property RecordAlias: TNullableRecordAlias read fRecordAlias write fRecordAlias; end; + TSysUser2 = class + private + FUserName: string; + fRoles: TUserRoles; + fRecordAlias: TNullableRecordAlias; + public + constructor Create(aUserName: string; aRoles: TUserRoles); + property UserName: string read FUserName write FUserName; + // Here we are using the custom-serialized type TUserRoles + property Roles: TUserRoles read fRoles write fRoles; + end; + + TArrayTest = class private fStrings: TArray; @@ -161,4 +174,13 @@ begin inherited; end; +{ TSysUser2 } + +constructor TSysUser2.Create(aUserName: string; aRoles: TUserRoles); +begin + inherited Create; + FUserName := aUserName; + fRoles := aRoles; +end; + end. diff --git a/samples/renders/RenderSampleControllerU.pas b/samples/renders/RenderSampleControllerU.pas index 6fcfb7a1..bd88170d 100644 --- a/samples/renders/RenderSampleControllerU.pas +++ b/samples/renders/RenderSampleControllerU.pas @@ -243,8 +243,13 @@ type procedure RaiseExceptionHTML; [MVCHTTPMethod([httpGET])] - [MVCPath('/customserializationtype')] - procedure GetCustomSerializationType; + [MVCPath('/customserializationtype/root')] + procedure GetCustomSerializationTypeROOT; + + [MVCHTTPMethod([httpGET])] + [MVCPath('/customserializationtype/attribute')] + procedure GetCustomSerializationTypeATTRIBUTE; + [MVCHTTPMethod([httpGET])] [MVCPath('/simplearray')] @@ -716,9 +721,15 @@ begin end; end; -procedure TRenderSampleController.GetCustomSerializationType; +procedure TRenderSampleController.GetCustomSerializationTypeATTRIBUTE; begin - // TSysUser contains a type with a custom serializer + // TSysUser2 contains a type with a custom serializer + Render(TSysUser2.Create('daniele', ['poweruser', 'role1', 'role2']), True); +end; + +procedure TRenderSampleController.GetCustomSerializationTypeROOT; +begin + // TSysUser is a type with a custom serializer Render(TSysUser.Create('daniele', ['poweruser', 'role1', 'role2']), True); end; diff --git a/samples/renders/WebModuleU.dfm b/samples/renders/WebModuleU.dfm index 98f71a86..b74ecded 100644 --- a/samples/renders/WebModuleU.dfm +++ b/samples/renders/WebModuleU.dfm @@ -1,5 +1,4 @@ object WebModule1: TWebModule1 - OldCreateOrder = False OnCreate = WebModuleCreate Actions = <> Height = 344 diff --git a/samples/renders/WebModuleU.pas b/samples/renders/WebModuleU.pas index 2137c0fb..77936d0c 100644 --- a/samples/renders/WebModuleU.pas +++ b/samples/renders/WebModuleU.pas @@ -100,10 +100,13 @@ begin DMVC.SetViewEngine(TMVCMustacheViewEngine); // Register a custom serializer for TUserRoles (is compatible only with the default serializer) - // DMVC - // .Serializers - // .Items[TMVCMediaType.APPLICATION_JSON] - // .RegisterTypeSerializer(TypeInfo(TUserRoles), TUserRolesSerializer.Create); + DMVC + .Serializer(TMVCMediaType.APPLICATION_JSON) + .RegisterTypeSerializer(TypeInfo(TUserRoles), TUserRolesSerializer.Create); + + DMVC + .Serializer(TMVCMediaType.APPLICATION_JSON) + .RegisterTypeSerializer(TypeInfo(TSysUser), TSysUserSerializer.Create); // You can check how this custom type serializer works // calling http://localhost:8080/customserializationtype diff --git a/samples/renders/renders.dpr b/samples/renders/renders.dpr index e9af6e48..1e85527a 100644 --- a/samples/renders/renders.dpr +++ b/samples/renders/renders.dpr @@ -36,6 +36,7 @@ uses Web.WebReq, Web.WebBroker, MVCFramework.Console, + MVCFramework.Logger, WebModuleU in 'WebModuleU.pas' {WebModule1: TWebModule}, RenderSampleControllerU in 'RenderSampleControllerU.pas', BusinessObjectsU in '..\commons\BusinessObjectsU.pas', @@ -55,17 +56,17 @@ procedure RunServer(APort: Integer); var LServer: TIdHTTPWebBrokerBridge; begin - Writeln(Format('Starting HTTP Server or port %d', [APort])); + LogI(Format('Starting HTTP Server or port %d', [APort])); LServer := TIdHTTPWebBrokerBridge.Create(nil); try LServer.DefaultPort := APort; LServer.Active := True; TextColor(Red); - Writeln('DMVCFRAMEWORK VERSION: ', DMVCFRAMEWORK_VERSION); + LogI('DMVCFRAMEWORK VERSION: ' + DMVCFRAMEWORK_VERSION); ResetConsole; - Writeln('Press RETURN to stop the server'); + LogI('Press RETURN to stop the server'); WaitForReturn; - Writeln('Stopping...'); + LogI('Stopping...'); finally LServer.Free; end; @@ -74,13 +75,14 @@ end; begin ReportMemoryLeaksOnShutdown := True; MVCSerializeNulls := True; + UseConsoleLogger := True; try if WebRequestHandler <> nil then WebRequestHandler.WebModuleClass := WebModuleClass; RunServer(8080); except on E: Exception do - Writeln(E.ClassName, ': ', E.Message); + LogException(E, E.Message); end end. diff --git a/samples/renders/renders.dproj b/samples/renders/renders.dproj index e20f9475..8b23ffe1 100644 --- a/samples/renders/renders.dproj +++ b/samples/renders/renders.dproj @@ -98,6 +98,8 @@ CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) 1033 false + false + none false @@ -197,10 +199,8 @@ - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components diff --git a/samples/serversentevents/SSEControllerU.pas b/samples/serversentevents/SSEControllerU.pas index 917ebf4c..12565c2c 100644 --- a/samples/serversentevents/SSEControllerU.pas +++ b/samples/serversentevents/SSEControllerU.pas @@ -25,7 +25,7 @@ var lCurrentEventID: Integer; lSSEMessage: TSSEMessage; begin - Sleep(1000); + Sleep(500 + Random(2000)); lSSEMessage.Event := 'stockupdate'; lSSEMessage.Data := GetNextDataToSend(StrToIntDef(LastEventID, 0), lCurrentEventID); lSSEMessage.Id := lCurrentEventID.ToString; diff --git a/samples/serversentevents/SSESample.dproj b/samples/serversentevents/SSESample.dproj index 040dfb24..0acdea4a 100644 --- a/samples/serversentevents/SSESample.dproj +++ b/samples/serversentevents/SSESample.dproj @@ -1,7 +1,7 @@  {56928A09-5B7B-4920-ABAA-CB68F0AC2958} - 20.1 + 20.2 VCL SSESample.dpr True @@ -146,7 +146,7 @@ Microsoft Office XP Sample Automation Server Wrapper Components - + @@ -160,16 +160,6 @@ 0 - - - classes - 64 - - - classes - 64 - - res\xml @@ -180,12 +170,6 @@ 1 - - - library\lib\armeabi-v7a - 1 - - library\lib\armeabi diff --git a/samples/serversentevents2/bin/serversentevent.db b/samples/serversentevents2/bin/serversentevent.db index adb36303..118c2b56 100644 Binary files a/samples/serversentevents2/bin/serversentevent.db and b/samples/serversentevents2/bin/serversentevent.db differ diff --git a/samples/serversideviews_templatepro/bin/people.data b/samples/serversideviews_templatepro/bin/people.data index 67bf8345..80a572ae 100644 --- a/samples/serversideviews_templatepro/bin/people.data +++ b/samples/serversideviews_templatepro/bin/people.data @@ -1 +1 @@ -[{"first_name":"Daniele","last_name":"Teti","age":43,"devices":[],"guid":"49E8419B66C744529D63DB292389D541"},{"first_name":"Peter","last_name":"Parker","age":23,"devices":[],"guid":"C5489969A04D4AE4B00D4FC50C8ADB5C"},{"first_name":"Bruce","last_name":"Banner","age":50,"devices":[],"guid":"B41D180F30584558B4F4A1AAF849FFA3"},{"first_name":"Sue","last_name":"Storm","age":33,"devices":[],"guid":"3F058118B8C6470D9684E127BC30A84A"},{"first_name":"Scott","last_name":"Summer","age":35,"devices":[],"guid":"3518D8C6F60E42D19C5A7250ADEADC33"},{"first_name":"Reed","last_name":"Richards","age":45,"devices":["smartphone","desktop"],"guid":"09C85C9DEB714476AADB9EB0AD689536"}] \ No newline at end of file +[{"first_name":"Daniele","last_name":"Teti","age":43,"devices":[],"guid":"49E8419B66C744529D63DB292389D541"},{"first_name":"Peter","last_name":"Parker","age":23,"devices":[],"guid":"C5489969A04D4AE4B00D4FC50C8ADB5C"},{"first_name":"Bruce","last_name":"Banner","age":50,"devices":[],"guid":"B41D180F30584558B4F4A1AAF849FFA3"},{"first_name":"Sue","last_name":"Storm","age":33,"devices":[],"guid":"3F058118B8C6470D9684E127BC30A84A"},{"first_name":"Scott","last_name":"Summer","age":35,"devices":[],"guid":"3518D8C6F60E42D19C5A7250ADEADC33"},{"first_name":"Reed","last_name":"Richards","age":45,"devices":["smartphone","desktop"],"guid":"09C85C9DEB714476AADB9EB0AD689536"},{"first_name":"Paolino","last_name":"Paperino","age":34,"devices":["dumbphone","laptop"],"guid":"40E3AA589440403C851D28FD649735E8"},{"first_name":"Paolino","last_name":"Paperino","age":34,"devices":["dumbphone","laptop"],"guid":"A9F3E3B5F6D344EC93C47C6E2B721B16"}] \ No newline at end of file diff --git a/samples/sessioncustom/CustomSessionSample.dproj b/samples/sessioncustom/CustomSessionSample.dproj index bddc5f11..5e14e9c4 100644 --- a/samples/sessioncustom/CustomSessionSample.dproj +++ b/samples/sessioncustom/CustomSessionSample.dproj @@ -1,7 +1,7 @@  {180D0369-D404-417C-8F18-6DE283368DE3} - 19.5 + 20.2 VCL CustomSessionSample.dpr True @@ -9,6 +9,7 @@ Win32 1 Console + CustomSessionSample true @@ -154,7 +155,7 @@ Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server - + @@ -164,16 +165,6 @@ 0 - - - classes - 64 - - - classes - 64 - - res\xml @@ -184,12 +175,6 @@ 1 - - - library\lib\armeabi-v7a - 1 - - library\lib\armeabi @@ -242,6 +227,16 @@ 1 + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + res\values @@ -262,6 +257,66 @@ 1 + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + res\values @@ -272,6 +327,16 @@ 1 + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + res\drawable @@ -442,6 +507,56 @@ 1 + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + 1 @@ -619,6 +734,9 @@ 1 + + 1 + @@ -880,6 +998,7 @@ + True diff --git a/samples/sessions/AppControllerU.pas b/samples/sessions/AppControllerU.pas index 5fa67ad2..16e65c5b 100644 --- a/samples/sessions/AppControllerU.pas +++ b/samples/sessions/AppControllerU.pas @@ -53,7 +53,7 @@ begin end else begin - RenderStatusMessage(http_status.BadRequest, 'Session not created. Do login first'); + Render(http_status.BadRequest, 'Session not created. Do login first'); end; end; diff --git a/samples/sessions/SessionSample.dpr b/samples/sessions/SessionSample.dpr index bc2c48ea..3088c16d 100644 --- a/samples/sessions/SessionSample.dpr +++ b/samples/sessions/SessionSample.dpr @@ -7,14 +7,11 @@ uses System.SysUtils, MVCFramework, MVCFramework.Signal, - + MVCFramework.Logger, {$IFDEF MSWINDOWS} - Winapi.Windows, Winapi.ShellAPI, - {$ENDIF} - Web.WebReq, Web.WebBroker, IdHTTPWebBrokerBridge, @@ -28,7 +25,7 @@ procedure RunServer(APort: Integer); var LServer: TIdHTTPWebBrokerBridge; begin - Writeln(Format('Starting HTTP Server or port %d', [APort])); + LogI(Format('Starting HTTP Server or port %d', [APort])); LServer := TIdHTTPWebBrokerBridge.Create(nil); try LServer.DefaultPort := APort; @@ -36,7 +33,7 @@ begin {$IFDEF MSWINDOWS} ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort) + '/login/john'), nil, nil, SW_SHOW); {$ENDIF} - Writeln('CTRL+C to stop the server'); + LogI('CTRL+C to stop the server'); WaitForTerminationSignal; EnterInShutdownState; finally @@ -53,7 +50,7 @@ begin RunServer(8080); except on E: Exception do - Writeln(E.ClassName, ': ', E.Message); + LogI(E.ClassName + ': ' + E.Message); end end. diff --git a/samples/sessions/SessionSample.dproj b/samples/sessions/SessionSample.dproj index fdcf0724..d32f0c15 100644 --- a/samples/sessions/SessionSample.dproj +++ b/samples/sessions/SessionSample.dproj @@ -1,7 +1,7 @@  {F9CBCE21-869A-478F-992C-88FCAC97BC8B} - 19.5 + 20.2 VCL SessionSample.dpr True @@ -9,6 +9,7 @@ Win32 1 Console + SessionSample true @@ -153,7 +154,7 @@ Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server - + @@ -163,16 +164,6 @@ 0 - - - classes - 64 - - - classes - 64 - - res\xml @@ -183,12 +174,6 @@ 1 - - - library\lib\armeabi-v7a - 1 - - library\lib\armeabi @@ -241,6 +226,16 @@ 1 + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + res\values @@ -261,6 +256,66 @@ 1 + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + res\values @@ -271,6 +326,16 @@ 1 + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + res\drawable @@ -441,6 +506,56 @@ 1 + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + 1 @@ -546,6 +661,130 @@ 0 + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset @@ -746,127 +985,6 @@ 1 - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - @@ -879,6 +997,7 @@ + True diff --git a/samples/simple_api_using_mvcactiverecord/CustomersControllerU.pas b/samples/simple_api_using_mvcactiverecord/CustomersControllerU.pas index 363fd267..05d5a921 100644 --- a/samples/simple_api_using_mvcactiverecord/CustomersControllerU.pas +++ b/samples/simple_api_using_mvcactiverecord/CustomersControllerU.pas @@ -16,15 +16,15 @@ type public [MVCPath('/($ID)')] [MVCHTTPMethods([httpGET])] - procedure GetCustomerByID(const ID: Integer); + function GetCustomerByID(const ID: Integer): TCustomer; [MVCPath] [MVCHTTPMethods([httpGET])] - procedure GetCustomers([MVCFromQueryString('rql','')] RQLFilter: String); + function GetCustomers([MVCFromQueryString('rql','')] RQLFilter: String): TObjectList; [MVCPath] [MVCHTTPMethods([httpPOST])] - procedure CreateCustomer([MVCFromBody] const Customer: TCustomer); + function CreateCustomer([MVCFromBody] const Customer: TCustomer): IMVCResponse; [MVCPath('/_bulk')] [MVCHTTPMethods([httpPOST])] @@ -43,20 +43,20 @@ uses { TCustomersController } -procedure TCustomersController.CreateCustomer(const Customer: TCustomer); +function TCustomersController.CreateCustomer(const Customer: TCustomer): IMVCResponse; begin Customer.Insert; - Render201Created('/api/customers/' + Customer.ID.Value.ToString); + Result := CreatedResponse('/api/customers/' + Customer.ID.Value.ToString); end; -procedure TCustomersController.GetCustomerByID(const ID: Integer); +function TCustomersController.GetCustomerByID(const ID: Integer): TCustomer; begin - Render(ObjectDict().Add('data', TMVCActiveRecord.GetByPK(ID))); + Result := TMVCActiveRecord.GetByPK(ID); end; -procedure TCustomersController.GetCustomers([MVCFromQueryString('rql','')] RQLFilter: String); +function TCustomersController.GetCustomers([MVCFromQueryString('rql','')] RQLFilter: String): TObjectList; begin - Render(ObjectDict().Add('data', TMVCActiveRecord.SelectRQL(RQLFilter, 1000))); + Result := TMVCActiveRecord.SelectRQL(RQLFilter, 1000); end; procedure TCustomersController.BulkCreateCustomers(const Customers: TObjectList); diff --git a/sources/MVCFramework.Serializer.Text.pas b/sources/MVCFramework.Serializer.Text.pas index 8b16472c..a51ff35f 100644 --- a/sources/MVCFramework.Serializer.Text.pas +++ b/sources/MVCFramework.Serializer.Text.pas @@ -345,11 +345,12 @@ begin lErrResponse.ClassName, lErrResponse.AppErrorCode, nil); - end; - - if Result.IsEmpty then + end else if aObject = nil then begin - RaiseNotImplemented + Result := ''; + end else + begin + RaiseNotImplemented; end; end; diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 27710d90..0a659cc1 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2859,30 +2859,37 @@ begin begin lResponseObject := lInvokeResult.AsObject; try - // https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0 - if lResponseObject is TDataSet then + if lResponseObject <> nil then begin - lSelectedController.Render(TDataSet(lResponseObject), False); - end - else if lResponseObject is TStream then - begin - lContext.Response.RawWebResponse.Content := EmptyStr; - lContext.Response.RawWebResponse.ContentType := lContext.Response.ContentType; - lContext.Response.RawWebResponse.ContentStream := TStream(lResponseObject); - lContext.Response.RawWebResponse.FreeContentStream := True; - lResponseObject := nil; //do not free it!! - end - else if lResponseObject is TMVCResponse then - begin - TMVCRenderer.InternalRenderMVCResponse(lSelectedController, TMVCResponse(lResponseObject)); - end - else if (not lResponseObject.InheritsFrom(TJsonBaseObject)) and TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then - begin - lSelectedController.Render(lObjList); + // https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0 + if lResponseObject is TDataSet then + begin + lSelectedController.Render(TDataSet(lResponseObject), False); + end + else if lResponseObject is TStream then + begin + lContext.Response.RawWebResponse.Content := EmptyStr; + lContext.Response.RawWebResponse.ContentType := lContext.Response.ContentType; + lContext.Response.RawWebResponse.ContentStream := TStream(lResponseObject); + lContext.Response.RawWebResponse.FreeContentStream := True; + lResponseObject := nil; //do not free it!! + end + else if lResponseObject is TMVCResponse then + begin + TMVCRenderer.InternalRenderMVCResponse(lSelectedController, TMVCResponse(lResponseObject)); + end + else if (not lResponseObject.InheritsFrom(TJsonBaseObject)) and TDuckTypedList.CanBeWrappedAsList(lResponseObject, lObjList) then + begin + lSelectedController.Render(lObjList); + end + else + begin + lSelectedController.Render(lResponseObject, False); + end; end else begin - lSelectedController.Render(lResponseObject, False); + lSelectedController.Render(TObject(nil)); end; finally lResponseObject.Free;