From 028089969a4f5e755f1413982339f778bf80e165 Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Mon, 11 May 2020 23:39:43 +0200 Subject: [PATCH] `TMVCEngine.Config` property is now read-only. Can be changed only in the anonymous method injected in the constructor. (All the samples have been updated - from an idea of @Spinettato a.k.a. Danielino) --- .angulardoc.json | 4 + 3_2_0_breaking_changes.md | 3 +- README.md | 56 +- .../Controllers/RoutingSampleControllerU.pas | 12 +- samples/ISAPI/WebModules/WebModuleU.pas | 11 +- .../WebModuleUnit1.pas | 13 +- samples/basicdemo_server/WebModuleUnit1.pas | 7 +- samples/fileupload/WebModuleUnit1.pas | 13 +- .../Win32/Debug/uploadedfiles/database.png | Bin 0 -> 31955 bytes samples/jsonwebtoken/WebModuleUnit1.pas | 18 +- .../WebModuleUnit1.pas | 10 +- samples/middleware/WebModuleUnit1.pas | 10 +- .../OutputCacheWithRedis.dproj | 518 +++++++++++++++--- samples/outputcachewithredis/WebModuleU.pas | 12 +- samples/renders/renders.dpr | 2 +- samples/renders/renders.dproj | 36 +- samples/servercontainer/WebModuleUnit1.pas | 15 +- samples/sessioncustom/WebModuleUnit1.pas | 17 +- samples/soaprest/bin/www/index.html | 2 +- samples/soaprest/wmSOAPRESTU.dfm | 1 + samples/soaprest/wmSOAPRESTU.pas | 13 +- samples/sslserver/WebModuleUnit1.pas | 12 +- samples/sslserver/bin/cacert.pem | 34 ++ samples/sslserver/bin/privkey.pem | 51 ++ .../winecellarserver/MainWebModuleUnit.pas | 3 +- sources/MVCFramework.Commons.pas | 50 +- sources/MVCFramework.pas | 1 + unittests/general/Several/bin/sqlitetest.db | Bin 0 -> 49152 bytes 28 files changed, 732 insertions(+), 192 deletions(-) create mode 100644 .angulardoc.json create mode 100644 samples/fileupload/Win32/Debug/uploadedfiles/database.png create mode 100644 samples/sslserver/bin/cacert.pem create mode 100644 samples/sslserver/bin/privkey.pem create mode 100644 unittests/general/Several/bin/sqlitetest.db diff --git a/.angulardoc.json b/.angulardoc.json new file mode 100644 index 00000000..c3cc19f7 --- /dev/null +++ b/.angulardoc.json @@ -0,0 +1,4 @@ +{ + "repoId": "597fc48e-dd8a-489c-9aa4-175e8fd8d673", + "lastSync": 0 +} \ No newline at end of file diff --git a/3_2_0_breaking_changes.md b/3_2_0_breaking_changes.md index 6f3ad79d..e962639e 100644 --- a/3_2_0_breaking_changes.md +++ b/3_2_0_breaking_changes.md @@ -4,4 +4,5 @@ - `TDataSetHolder` class now renders data in a property called `data` (previously was `items`) - The default header used by JWT middleware is now `Authorization` (previously was `Authentication`) - Middleware `OnAfterControllerAction` are now invoked in the same order of `OnBeforeControllerAction` (previously were invoked in reversed order). -- `IMVCMiddleware` has got a new method called after the request processing: `OnAfterRouting` . It is called even if no action is executed. If you don't need it, implement the method and leave it empty. \ No newline at end of file +- `IMVCMiddleware` has got a new method called after the request processing: `OnAfterRouting` . It is called even if no action is executed. If you don't need it, implement the method and leave it empty. +- `TMVCEngine` is no more responsible for static file serviing. If you need static files used the new `TMVCStaticFilesMiddleware` (check the sample). \ No newline at end of file diff --git a/README.md b/README.md index 4141b447..ad8ddc34 100644 --- a/README.md +++ b/README.md @@ -370,39 +370,23 @@ begin end; ``` - New! Custom Exception Handling (Based on work of [David Moorhouse](https://github.com/fastbike)). Sample "custom_exception_handling" show how to use it. - - Improved! Exceptions rendering while using MIME types different to `application/json`. - - SSL Server support for `TMVCListener` (Thanks to [Sven Harazim](https://github.com/landrix)) - - Improved! Datasets serialization speed improvement. In some case the performance [improves of 2 order of magnitude](https://github.com/danieleteti/delphimvcframework/issues/205#issuecomment-479513158). (Thanks to https://github.com/pedrooliveira01) - - New! Added `in` operator in RQL parser (Thank you to [João Antônio Duarte](https://github.com/joaoduarte19) for his initial work on this) - - New! Added `TMVCActiveRecord.Count(RQL)` to count record based on RQL criteria - - New! `TMVCActiveRecord` can handle non autogenerated primary key. - - New! Experimental (alpha stage) support for Android servers! - - New! Added support for `X-HTTP-Method-Override` to work behind corporate firewalls. - - New Sample! Server in DLL - - Added new method in the dataset helper to load data into a dataset from a specific JSONArray property of a JSONObject `procedure TDataSetHelper.LoadJSONArrayFromJSONObjectProperty(const AJSONObjectString: string; const aPropertyName: String);` - - Improved! New constants defined in `HTTP_STATUS` to better describe the http status response. - - Improved! Now Firebird RQL' SQLGenerator can include primary key in `CreateInsert` if not autogenerated. - - New! Added support for `TArray`, `TArray` and `TArray` in default JSON serializer (Thank you [Pedro Oliveira](https://github.com/pedrooliveira01)) - - Improved JWT Standard Compliance! Thanks to [Vinicius Sanchez](https://github.com/viniciussanchez) for his work on [issue #241](https://github.com/danieleteti/delphimvcframework/issues/241) - - Improved! DMVCFramework now has 130+ unit tests that checks its functionalities at each build! - +- Improved! Better exception handling in `OnBeforeDispatch` (Thanks to [Spinettaro](https://github.com/spinettaro)) - New! `StrToJSONObject` function to safely parse a string into a JSON object. - - New! Serialization callback for custom `TDataSet` descendants serialization in `TMVCJsonDataObjectsSerializer`. ```delphi procedure TMainForm.btnDataSetToJSONArrayClick(Sender: TObject); @@ -572,10 +556,6 @@ end; -- **Breaking Change!** In `MVCActiveRecord` attribute `MVCPrimaryKey` has been removed and merged with `MVCTableField`, so now `TMVCActiveRecordFieldOption` is a set of `foPrimaryKey`, `foAutoGenerated`, `foTransient` (check `activerecord_showcase.dproj` sample). - -- **Breaking Change!** Middleware `OnAfterControllerAction` are now invoked in the same order of `OnBeforeControllerAction` (previously were invoked in reversed order). - - **Deprecated!** `TDataSetHolder` is deprecated! Use the shining new `ObjectDict(boolean)` instead. - Added ability to serialize/deserialize types enumerated by an array of mapped values (Thanks to [João Antônio Duarte](https://github.com/joaoduarte19)) @@ -622,6 +602,40 @@ end; |Delphi 10.1 Berlin| `packages\d101\dmvcframework_group.groupproj`| |Delphi 10.0 Seattle| `packages\d100\dmvcframework_group.groupproj`| +### Breaking Changes in 3.2.0-boron + +- In `MVCActiveRecord` attribute `MVCPrimaryKey` has been removed and merged with `MVCTableField`, so now `TMVCActiveRecordFieldOption` is a set of `foPrimaryKey`, `foAutoGenerated`, `foTransient` (check `activerecord_showcase.dproj` sample). + +- Middleware `OnAfterControllerAction` are now invoked in the same order of `OnBeforeControllerAction` (previously were invoked in reversed order). + +- `TMVCEngine` is no more responsible for static file serving. If you need static files used the new `TMVCStaticFilesMiddleware` (check the sample). As consequence `TMVCConfigKey.DocumentRoot`, `TMVCConfigKey.IndexDocument` and `TMVCConfigKey.FallbackResource` are no more available. + +- `TMVCEngine.Config` property is now read-only. Can be changed only in the anonymous method injected in the constructor. + + ```delphi + // This is valid + //////////////////////////////////////// + FMVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + // session timeout (0 means session cookie) + Config[TMVCConfigKey.SessionTimeout] := '0'; + //Other Configurations + end); + FMVC.AddController(TMyController); + + + // This is not valid (exception is raised) + ///////////////////////////////////////// + + FMVC := TMVCEngine.Create(Self);, + FMVC.Config[TMVCConfigKey.SessionTimeout] := '0'; {run-time error here} + FMVC.AddController(TMyController); + + ``` + + + ### Bug Fixes in 3.2.0-boron - Fixed! [issue38](https://github.com/danieleteti/delphimvcframework/issues/38) diff --git a/samples/ISAPI/Controllers/RoutingSampleControllerU.pas b/samples/ISAPI/Controllers/RoutingSampleControllerU.pas index de8607cf..88b70536 100644 --- a/samples/ISAPI/Controllers/RoutingSampleControllerU.pas +++ b/samples/ISAPI/Controllers/RoutingSampleControllerU.pas @@ -17,7 +17,7 @@ type [MVCPath('/search/($searchtext)/($page)')] [MVCProduces('text/plain', 'UTF-8')] [MVCConsumes('text/html')] - procedure SearchCustomers(CTX: TWebContext); + procedure SearchCustomers; [MVCHTTPMethod([httpGet])] [MVCPath('/people/($id)')] @@ -54,17 +54,17 @@ begin Render('This is the root path'); end; -procedure TRoutingSampleController.SearchCustomers(CTX: TWebContext); +procedure TRoutingSampleController.SearchCustomers; var search: string; P: Integer; orderby: string; begin - search := CTX.Request.Params['searchtext']; - P := CTX.Request.ParamsAsInteger['page']; + search := Context.Request.Params['searchtext']; + P := Context.Request.ParamsAsInteger['page']; orderby := ''; - if CTX.Request.QueryStringParamExists('order') then - orderby := CTX.Request.QueryStringParam('order'); + if Context.Request.QueryStringParamExists('order') then + orderby := Context.Request.QueryStringParam('order'); Render(Format( 'SEARCHTEXT: "%s"' + sLineBreak + 'PAGE: %d' + sLineBreak + diff --git a/samples/ISAPI/WebModules/WebModuleU.pas b/samples/ISAPI/WebModules/WebModuleU.pas index fb00a690..049c06f3 100644 --- a/samples/ISAPI/WebModules/WebModuleU.pas +++ b/samples/ISAPI/WebModules/WebModuleU.pas @@ -22,14 +22,17 @@ implementation {$R *.dfm} -uses RoutingSampleControllerU; +uses RoutingSampleControllerU, MVCFramework.Commons; procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - DMVC := TMVCEngine.Create(self); + DMVC := TMVCEngine.Create(self, + procedure(Config: TMVCConfig) + begin + if IsConsole then + DMVC.Config['ISAPI_PATH'] := '/sampleisapi/isapiapp.dll'; + end); DMVC.AddController(TRoutingSampleController); - if IsConsole then - DMVC.Config['ISAPI_PATH'] := '/sampleisapi/isapiapp.dll'; end; end. diff --git a/samples/authenticationauthorization/WebModuleUnit1.pas b/samples/authenticationauthorization/WebModuleUnit1.pas index b6f967bf..2fe5d54a 100644 --- a/samples/authenticationauthorization/WebModuleUnit1.pas +++ b/samples/authenticationauthorization/WebModuleUnit1.pas @@ -37,16 +37,19 @@ uses procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - MVC := TMVCEngine.Create(Self); - MVC.Config[TMVCConfigKey.SessionTimeout] := '30'; - MVC.Config[TMVCConfigKey.DefaultContentType] := 'text/html'; + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.SessionTimeout] := '30'; + Config[TMVCConfigKey.DefaultContentType] := 'text/html'; + end); MVC .AddController(TApp1MainController) .AddController(TAdminController) .AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(TAuthenticationSample.Create)) .AddMiddleware(TMVCStaticFilesMiddleware.Create( - '/', { StaticFilesPath } - '..\..\www' { DocumentRoot } + '/', { StaticFilesPath } + '..\..\www' { DocumentRoot } )); end; diff --git a/samples/basicdemo_server/WebModuleUnit1.pas b/samples/basicdemo_server/WebModuleUnit1.pas index ac2670b6..a97ec670 100644 --- a/samples/basicdemo_server/WebModuleUnit1.pas +++ b/samples/basicdemo_server/WebModuleUnit1.pas @@ -34,8 +34,11 @@ uses procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - MVC := TMVCEngine.Create(Self); - MVC.Config[TMVCConfigKey.ViewPath] := '.\www\public_html'; + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.ViewPath] := '.\www\public_html'; + end); // Web files MVC.AddMiddleware(TMVCStaticFilesMiddleware.Create('/', '.\www\public_html')); diff --git a/samples/fileupload/WebModuleUnit1.pas b/samples/fileupload/WebModuleUnit1.pas index 30d547e4..661481c9 100644 --- a/samples/fileupload/WebModuleUnit1.pas +++ b/samples/fileupload/WebModuleUnit1.pas @@ -36,18 +36,21 @@ uses procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - MVC := TMVCEngine.Create(self); + MVC := TMVCEngine.Create(self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.ViewPath] := + ExtractFilePath(GetModuleName(HInstance)) + '..\..\templates'; + Config[TMVCConfigKey.DefaultContentType] := TMVCMediaType.TEXT_HTML; + end); MVC.AddController(TFileUploadController); MVC.AddMiddleware(TMVCTraceMiddleware.Create); MVC.AddMiddleware(TMVCStaticFilesMiddleware.Create( '/', { StaticFilesPath } ExtractFilePath(GetModuleName(HInstance)) + '..\..\document_root', { DocumentRoot } - 'index.html' {IndexDocument - Before it was named fallbackresource} + 'index.html' { IndexDocument - Before it was named fallbackresource } )); MVC.SetViewEngine(TMVCTemplateProViewEngine); - MVC.Config[TMVCConfigKey.ViewPath] := ExtractFilePath(GetModuleName(HInstance) - ) + '..\..\templates'; - MVC.Config[TMVCConfigKey.DefaultContentType] := TMVCMediaType.TEXT_HTML; end; diff --git a/samples/fileupload/Win32/Debug/uploadedfiles/database.png b/samples/fileupload/Win32/Debug/uploadedfiles/database.png new file mode 100644 index 0000000000000000000000000000000000000000..477ad16bad38911c76007336598ffd5604b4f29f GIT binary patch literal 31955 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 {BE3A3D14-17E0-45C1-BD21-4710DE4CBCC2} - 18.6 + 18.8 VCL OutputCacheWithRedis.dpr True @@ -18,18 +18,8 @@ Base true - - true - Base - true - - - true - Base - true - - - true + + true Base true @@ -38,6 +28,11 @@ Base true + + true + Base + true + true Base @@ -117,66 +112,50 @@ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= Debug + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png + $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png - - $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png - $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png - $(MSBuildProjectName) - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png + + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= Debug - true - $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png - $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png - $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png - iPhoneAndiPad - CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes= - - - $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png - $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png - $(MSBuildProjectName) - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png - Debug - true - $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png - $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png - $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png - iPhoneAndiPad - CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes= - - - $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png - $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png - $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png - true - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png - $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png - $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png - $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png - CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes= - iPhoneAndiPad + true + Base + true + true + true + true + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png + android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar + true + true + true + true + $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png + $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png + true + $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png Debug CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user + + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user + Debug + true + Base + true + (None) .\bin @@ -341,12 +320,20 @@ classes 1 + + classes + 1 + res\xml 1 + + res\xml + 1 + @@ -359,12 +346,26 @@ library\lib\armeabi 1 + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + library\lib\mips 1 + + library\lib\mips + 1 + @@ -372,84 +373,216 @@ library\lib\armeabi-v7a 1 + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + res\drawable 1 + + res\drawable + 1 + res\values 1 + + res\values + 1 + res\values-v21 1 + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + res\drawable 1 + + res\drawable + 1 + res\drawable-xxhdpi 1 + + res\drawable-xxhdpi + 1 + res\drawable-ldpi 1 + + res\drawable-ldpi + 1 + res\drawable-mdpi 1 + + res\drawable-mdpi + 1 + res\drawable-hdpi 1 + + res\drawable-hdpi + 1 + res\drawable-xhdpi 1 + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + res\drawable-small 1 + + res\drawable-small + 1 + res\drawable-normal 1 + + res\drawable-normal + 1 + res\drawable-large 1 + + res\drawable-large + 1 + res\drawable-xlarge 1 + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + @@ -519,6 +652,9 @@ 0 + + 0 + 0 @@ -549,6 +685,17 @@ 1 + + + 1 + + + 1 + + + 1 + + 1 @@ -560,6 +707,39 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 @@ -571,6 +751,61 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 @@ -582,6 +817,116 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 @@ -615,10 +960,35 @@ 1 + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + 1 + + 1 + @@ -662,6 +1032,10 @@ library\lib\armeabi-v7a 1 + + library\lib\arm64-v8a + 1 + 1 @@ -684,6 +1058,12 @@ 0 + + + library\lib\armeabi-v7a + 1 + + 1 @@ -721,13 +1101,13 @@ + False - False - False - False + False False + False True True diff --git a/samples/outputcachewithredis/WebModuleU.pas b/samples/outputcachewithredis/WebModuleU.pas index fb854b25..b4da146a 100644 --- a/samples/outputcachewithredis/WebModuleU.pas +++ b/samples/outputcachewithredis/WebModuleU.pas @@ -27,7 +27,7 @@ implementation {$R *.dfm} -uses PeopleControllerU; +uses PeopleControllerU, MVCFramework.Commons; procedure TwmMain.WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); @@ -37,10 +37,12 @@ end; procedure TwmMain.WebModuleCreate(Sender: TObject); begin - MVC := TMVCEngine.Create(Self); - - // required by the TMVCCacheController - MVC.Config['redis_connection_string'] := '127.0.0.1:6379'; + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + // required by the TMVCCacheController + MVC.Config['redis_connection_string'] := '127.0.0.1:6379'; + end); MVC.AddController(TPeopleController); end; diff --git a/samples/renders/renders.dpr b/samples/renders/renders.dpr index 98407ec0..f8278802 100644 --- a/samples/renders/renders.dpr +++ b/samples/renders/renders.dpr @@ -2,7 +2,7 @@ // // Delphi MVC Framework // -// Copyright (c) 2010-2019 Daniele Teti and the DMVCFramework Team +// Copyright (c) 2010-2020 Daniele Teti and the DMVCFramework Team // // https://github.com/danieleteti/delphimvcframework // diff --git a/samples/renders/renders.dproj b/samples/renders/renders.dproj index 58dab15e..a627a7d1 100644 --- a/samples/renders/renders.dproj +++ b/samples/renders/renders.dproj @@ -360,6 +360,12 @@ true + + + .\ + true + + .\ @@ -372,12 +378,24 @@ true + + + .\ + true + + .\ true + + + renders.exe + true + + .\ @@ -389,24 +407,6 @@ true - - - renders.exe - true - - - - - .\ - true - - - - - .\ - true - - .\ diff --git a/samples/servercontainer/WebModuleUnit1.pas b/samples/servercontainer/WebModuleUnit1.pas index a5f12a80..0ac7a05d 100644 --- a/samples/servercontainer/WebModuleUnit1.pas +++ b/samples/servercontainer/WebModuleUnit1.pas @@ -26,19 +26,24 @@ implementation {$R *.dfm} + uses App1MainControllerU, - MVCFramework.Middleware.StaticFiles; + MVCFramework.Middleware.StaticFiles, MVCFramework.Commons; procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - FMVCEngine := TMVCEngine.Create(Self); - FMVCEngine.Config['view_path'] := '..\Debug\HTML5Application'; - FMVCEngine.AddController(TApp1MainController); + FMVCEngine := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config['view_path'] := '..\Debug\HTML5Application'; + end); + FMVCEngine.AddController( + TApp1MainController); FMVCEngine.AddMiddleware(TMVCStaticFilesMiddleware.Create( '/', { StaticFilesPath } 'HTML5Application\public_html', { DocumentRoot } - 'index.html' {IndexDocument - Before it was named fallbackresource} + 'index.html' { IndexDocument - Before it was named fallbackresource } )); end; diff --git a/samples/sessioncustom/WebModuleUnit1.pas b/samples/sessioncustom/WebModuleUnit1.pas index b09521d2..67b7349d 100644 --- a/samples/sessioncustom/WebModuleUnit1.pas +++ b/samples/sessioncustom/WebModuleUnit1.pas @@ -11,10 +11,8 @@ uses System.SysUtils, type TWebModule1 = class(TWebModule) procedure WebModuleCreate(Sender: TObject); - private MVC: TMVCEngine; - public { Public declarations } end; @@ -31,13 +29,14 @@ uses AppControllerU; procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - MVC := TMVCEngine.Create(Self); - MVC.Config[TMVCConfigKey.SessionTimeout] := '10'; // 10minutes - MVC.Config[TMVCConfigKey.DefaultContentType] := 'text/plain'; - - // comment the line to use default session type (memory) - MVC.Config[TMVCConfigKey.SessionType] := 'memoryController'; - + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.SessionTimeout] := '10'; // 10minutes + Config[TMVCConfigKey.DefaultContentType] := 'text/plain'; + // comment the line to use default session type (memory) + MVC.Config[TMVCConfigKey.SessionType] := 'memoryController'; + end); MVC.AddController(TApp1MainController); end; diff --git a/samples/soaprest/bin/www/index.html b/samples/soaprest/bin/www/index.html index 1dbb7bbc..86fa05cc 100644 --- a/samples/soaprest/bin/www/index.html +++ b/samples/soaprest/bin/www/index.html @@ -2,7 +2,7 @@

SOAP and REST

This example uses the allow_unhandled_action option to allow standard Delphi SOAP webservice functionality.

-

Visit /soap for WSDL

+

Visit /wsdl for WSDL

Visit /customer for Customer REST

\ No newline at end of file diff --git a/samples/soaprest/wmSOAPRESTU.dfm b/samples/soaprest/wmSOAPRESTU.dfm index ea12c0e1..b8d2af0e 100644 --- a/samples/soaprest/wmSOAPRESTU.dfm +++ b/samples/soaprest/wmSOAPRESTU.dfm @@ -29,6 +29,7 @@ object wmSOAPREST: TwmSOAPREST object WSDLHTMLPublish: TWSDLHTMLPublish WebDispatch.MethodType = mtAny WebDispatch.PathInfo = 'wsdl*' + TargetNamespace = 'http://tempuri.org/' PublishOptions = [poUTF8ContentType] Left = 60 Top = 123 diff --git a/samples/soaprest/wmSOAPRESTU.pas b/samples/soaprest/wmSOAPRESTU.pas index 784030a2..1bdb712d 100644 --- a/samples/soaprest/wmSOAPRESTU.pas +++ b/samples/soaprest/wmSOAPRESTU.pas @@ -31,19 +31,24 @@ implementation {$R *.dfm} + uses MVCFramework.Middleware.StaticFiles, RESTControllerCustomerU; procedure TwmSOAPREST.WebModuleCreate(Sender: TObject); begin - FMVCEngine := TMVCEngine.Create(self); - FMVCEngine.Config[TMVCConfigKey.AllowUnhandledAction] := 'true'; + FMVCEngine := TMVCEngine.Create(self, + procedure(Config: TMVCConfig) + begin + Config[TMVCConfigKey.AllowUnhandledAction] := 'true'; + end); FMVCEngine.AddController(TControllerCustomer); FMVCEngine.AddMiddleware(TMVCStaticFilesMiddleware.Create( '/', { StaticFilesPath } 'www', { DocumentRoot } - 'index.html' {IndexDocument - Before it was named fallbackresource} + 'index.html' { IndexDocument - Before it was named fallbackresource }, + False )); end; @@ -54,7 +59,7 @@ begin end; procedure TwmSOAPREST.wmSOAPRESTSoapActionAction(Sender: TObject; - Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); +Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin WSDLHTMLPublish.ServiceInfo(Sender, Request, Response, Handled); end; diff --git a/samples/sslserver/WebModuleUnit1.pas b/samples/sslserver/WebModuleUnit1.pas index f0c3cc10..cc3ee34e 100644 --- a/samples/sslserver/WebModuleUnit1.pas +++ b/samples/sslserver/WebModuleUnit1.pas @@ -24,19 +24,23 @@ implementation {$R *.dfm} -uses MyControllerU; +uses MyControllerU, MVCFramework.Commons; procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin - Response.Content := 'Web Server Application'; + Response.Content := 'DMVCFramework Server Application'; end; procedure TWebModule1.WebModuleCreate(Sender: TObject); begin - MVC := TMVCEngine.Create(Self); + MVC := TMVCEngine.Create(Self, + procedure(Config: TMVCConfig) + begin + Config['ISAPI_PATH'] := '/isapi32/myisapi.dll'; + end); MVC.AddController(TMyController); - MVC.Config['ISAPI_PATH'] := '/isapi32/myisapi.dll'; + end; procedure TWebModule1.WebModuleDestroy(Sender: TObject); diff --git a/samples/sslserver/bin/cacert.pem b/samples/sslserver/bin/cacert.pem new file mode 100644 index 00000000..b38b0272 --- /dev/null +++ b/samples/sslserver/bin/cacert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF9DCCA9ygAwIBAgIJAOFuHMKs/11KMA0GCSqGSIb3DQEBCwUAMIGOMQswCQYD +VQQGEwJJVDEOMAwGA1UECAwFSVRBTFkxDTALBgNVBAcMBFJPTUUxHzAdBgNVBAoM +FkJJVCBUSU1FIFBST0ZFU1NJT05BTFMxGjAYBgNVBAMMEXd3dy5taW9zZXJ2ZXIu +Y29tMSMwIQYJKoZIhvcNAQkBFhR3ZWJtYXN0ZXJAYml0dGltZS5pdDAeFw0xODA1 +MTYwNzM3NTJaFw0yMTA1MTUwNzM3NTJaMIGOMQswCQYDVQQGEwJJVDEOMAwGA1UE +CAwFSVRBTFkxDTALBgNVBAcMBFJPTUUxHzAdBgNVBAoMFkJJVCBUSU1FIFBST0ZF +U1NJT05BTFMxGjAYBgNVBAMMEXd3dy5taW9zZXJ2ZXIuY29tMSMwIQYJKoZIhvcN +AQkBFhR3ZWJtYXN0ZXJAYml0dGltZS5pdDCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAJxYF2WbI+vBbhb7qy5hA2CtYVdManSUTtr8f2CSRCMjfxAuaTdQ +Ga5y3pMW4iLNGJjnLpJOZvrHGsJbkkL/uUJh/Q9QQpaq0G+XHuZ9GVxq28/ZJDKV +wMemAh4JVNrPSCNOj/6ZD/3phM84a4L6wlLBMbPofeo9tEP/BV6PByPQfGDja8JY +mpC1r/TiUTdmk+ylM8Cjv8NLrrWjZnLxTNUTNtiXM0orBoKnwjazFujJNZI5hVdF +LMjNKFI3gS08o2jqlrmaNqNQFfll7ax/S1t4R8vIme7DfeOAll4iOq/QzYQ3Ilfj +9Z+j0viSomcia7s/7A2u+Ad4b5dhrjZOADxxps1qCynVGkU5cNyj7ra4V6CQSgwB +41EIJMgM5pEhrKf4yta3Xaob44/Ce7ThZil92P9o7h8AcYtrCZEcaaT3dbsUBz5e +UlMwJ9uSkk/cZ+v9uPg5TgFb0ib+fxbucVAet5jRmQthuJXLi+jRY8CKjH0PUj5u +soc/EY5xlIx/wKVJc7rgRzvqfZgrU3d5+XBL/f7SK6R6hKQ8wIYwpcIijzOnjiMz +YnsmEBf+V7l7xuVK8KYAbLkhw4tWUNVBJGrLhem23JKogfb+Ap7zvuUD+uJQDvkN +/i4cxKOOPFPihKNpJgtbmHlyJNBSzQ5mAAAQXJIDrNDB5FEI0veu1n7NAgMBAAGj +UzBRMB0GA1UdDgQWBBT70tiJ+vU0yMF/Q0e0QlIhO9RcmDAfBgNVHSMEGDAWgBT7 +0tiJ+vU0yMF/Q0e0QlIhO9RcmDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4ICAQAee/uDpIiiMm4N3gMCHODx6dYuGda3nbGIe5R/MeJJk01gIA/eFzRi +lXfBXQqSi4HckXK53kDLkQl6iZQTskhsCMqkazkCWZfzj9nNGSWXoOMDVARnH/eQ +BnmS8coiFBI3m3Dm7njAL7/yIFHd84RR3eu/diWM+oFMAQhP6mjo+egGDzxliav2 +IPbs0INYGwxVsX9eizw9bc6VNin4HH25uEd6YKw/NEC1Hh3PCdNIkzhi12lWtL7Y +L8bwwaNvq//nkpHmU1URYIC74ooRQ0pmzNu5Q+UgXJgNTOYKk8rViTGQEvvKbwc+ +2OMrHXwtpF5KHyktDGrpNQR9OQjcxcf2oVxSpp74oJkZhLpc0IydEEFXhlfNJTFp +H6imbyTPwgco8bnv1x6jhVr7tcumRBrdA0Xukathg4UkzAThZwkqBvDtJOpT9Whj +YgqVjpe1siWZkmUizSB/SSLFl9OlVD54pPY6hCNRU+iY113GzTP+aliExDfsGf4y +H1xyvXzM/tJ8s76IQfyihBpLn436J5Y59lHzUEhV30FGXzx4uwo2pk5YXDmSux1I +A5uMV80VjdWb/99orGK3XyN33twR9VSv253tsQtf9SeSID/U2+AYCEzPqNskZI/5 +x9rPErp4IlrYsxpxODAssVJ5pJxPE3TrtBXy22a2iof5LvW7muTlrQ== +-----END CERTIFICATE----- diff --git a/samples/sslserver/bin/privkey.pem b/samples/sslserver/bin/privkey.pem new file mode 100644 index 00000000..e418da9e --- /dev/null +++ b/samples/sslserver/bin/privkey.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/samples/winecellarserver/MainWebModuleUnit.pas b/samples/winecellarserver/MainWebModuleUnit.pas index c71468b8..b86c90df 100644 --- a/samples/winecellarserver/MainWebModuleUnit.pas +++ b/samples/winecellarserver/MainWebModuleUnit.pas @@ -32,6 +32,7 @@ uses {$R *.dfm} + procedure Twm.WebModuleCreate(Sender: TObject); begin MVCEngine := TMVCEngine.Create(self); @@ -39,7 +40,7 @@ begin MVCEngine.AddMiddleware(TMVCStaticFilesMiddleware.Create( '/', { StaticFilesPath } TPath.Combine(AppPath, '..\..\www'), { DocumentRoot } - 'index.html' {IndexDocument - Before it was named fallbackresource} + 'index.html' { IndexDocument - Before it was named fallbackresource } )); end; diff --git a/sources/MVCFramework.Commons.pas b/sources/MVCFramework.Commons.pas index a7cb2fbd..86ad4474 100644 --- a/sources/MVCFramework.Commons.pas +++ b/sources/MVCFramework.Commons.pas @@ -445,22 +445,22 @@ type function LinksData: TMVCStringDictionaryList; end; -// IMVCStringDictionary = interface -// ['{164117AD-8DDD-47F7-877C-453979707D10}'] -// function GetItems(const Key: string): string; -// procedure SetItems(const Key, Value: string); -// procedure Clear; -//// function Add(const Name, Value: string): IMVCStringDictionary; -// function TryGetValue(const Name: string; out Value: string): Boolean; overload; -// function TryGetValue(const Name: string; out Value: Integer): Boolean; overload; -// function Count: Integer; -// function GetEnumerator: TDictionary.TPairEnumerator; -// function ContainsKey(const Key: string): Boolean; -// function Keys: TArray; -// property Items[const Key: string]: string read GetItems; default; -// end; + // IMVCStringDictionary = interface + // ['{164117AD-8DDD-47F7-877C-453979707D10}'] + // function GetItems(const Key: string): string; + // procedure SetItems(const Key, Value: string); + // procedure Clear; + /// / function Add(const Name, Value: string): IMVCStringDictionary; + // function TryGetValue(const Name: string; out Value: string): Boolean; overload; + // function TryGetValue(const Name: string; out Value: Integer): Boolean; overload; + // function Count: Integer; + // function GetEnumerator: TDictionary.TPairEnumerator; + // function ContainsKey(const Key: string): Boolean; + // function Keys: TArray; + // property Items[const Key: string]: string read GetItems; default; + // end; - TMVCStringDictionary = class //(TInterfacedObject, IMVCStringDictionary) + TMVCStringDictionary = class // (TInterfacedObject, IMVCStringDictionary) strict private function GetItems(const Key: string): string; procedure SetItems(const Key, Value: string); @@ -540,16 +540,17 @@ type TMVCConfig = class sealed private FConfig: TMVCStringDictionary; - + FFreezed: Boolean; function GetValue(const AIndex: string): string; function GetValueAsInt64(const AIndex: string): Int64; procedure SetValue(const AIndex: string; const aValue: string); + procedure CheckNotFreezed; inline; protected { protected declarations } public constructor Create; destructor Destroy; override; - + procedure Freeze; function Keys: TArray; function ToString: string; override; procedure SaveToFile(const AFileName: string); @@ -861,10 +862,19 @@ end; { TMVCConfig } +procedure TMVCConfig.CheckNotFreezed; +begin + if FFreezed then + begin + raise EMVCException.Create('Configuration in freezed - no more changes allowed') at ReturnAddress; + end; +end; + constructor TMVCConfig.Create; begin inherited Create; FConfig := TMVCStringDictionary.Create; + FFreezed := False; end; destructor TMVCConfig.Destroy; @@ -873,6 +883,11 @@ begin inherited Destroy; end; +procedure TMVCConfig.Freeze; +begin + FFreezed := True; +end; + function TMVCConfig.GetValue(const AIndex: string): string; begin if FConfig.ContainsKey(AIndex) then @@ -922,6 +937,7 @@ end; procedure TMVCConfig.SetValue(const AIndex, aValue: string); begin + CheckNotFreezed; FConfig.Add(AIndex, aValue); end; diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index 1aa1fedb..8bf1b383 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -2012,6 +2012,7 @@ begin AConfigAction(FConfig); LogExitMethod('Custom configuration method'); end; + FConfig.Freeze; SaveCacheConfigValues; RegisterDefaultsSerializers; LoadSystemControllers; diff --git a/unittests/general/Several/bin/sqlitetest.db b/unittests/general/Several/bin/sqlitetest.db new file mode 100644 index 0000000000000000000000000000000000000000..cb26e000c35ab5cf1418b920cfb3fc7b6481de2c GIT binary patch literal 49152 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 U$V`NA^o+mA0Uw?2D9ft<1FE%wng9R* literal 0 HcmV?d00001