238 Commits

Author SHA1 Message Date
Jonathan Jenne
a3e1d34a7a Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2024-01-18 15:54:48 +01:00
Jonathan Jenne
a53c5154b0 jobs: version 2.4.0.0 2024-01-18 15:54:36 +01:00
Jonathan Jenne
6e5b192fb6 graphql: create history table before running 2024-01-18 15:54:25 +01:00
efdbed58df Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2024-01-15 10:29:18 +01:00
Jonathan Jenne
dc6ad9afac Remove Base.Test Project 2024-01-15 10:28:18 +01:00
38f330b94b Interfaces/Zugferd: Extension With ToUpper() and Substring(1) 2024-01-15 10:26:34 +01:00
Jonathan Jenne
9f11b2b7bc Interfaces/ZUGFeRD: check if any extension exists 2024-01-15 09:17:50 +01:00
Jonathan Jenne
4a2b64f73d Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2024-01-05 12:45:52 +01:00
Jonathan Jenne
12eef1de61 Database: Version 2.3.4.0 2024-01-05 12:45:26 +01:00
Jonathan Jenne
bdceababcf Database: log transaction mode, add datatable async functions 2024-01-05 12:45:17 +01:00
07d26cf70c Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2024-01-05 08:23:19 +01:00
0810983f86 WINDREAM CheckFileExistsinWM falsches Log 2024-01-05 08:23:04 +01:00
Jonathan Jenne
9deeb35ad7 clean up 2024-01-03 15:19:29 +01:00
Jonathan Jenne
63ddbaeacf Jobs: Version 2.3.0.1 2023-12-20 15:30:01 +01:00
Jonathan Jenne
71e9fe7cd2 Jobs: Improve logging 2023-12-20 15:29:27 +01:00
Jonathan Jenne
726c3481e5 Jobs: Fix logging 2023-12-20 15:16:27 +01:00
Jonathan Jenne
30c602a9bf clean up 2023-12-20 15:09:10 +01:00
Jonathan Jenne
5b2ba2eff2 Jobs: Version 2.3.0.0 2023-12-20 15:09:06 +01:00
Jonathan Jenne
04577f3b61 Jobs: add check for file age 2023-12-20 15:08:04 +01:00
Jonathan Jenne
8da8bd18a7 Improve logging with auth type none 2023-11-16 10:18:53 +01:00
Jonathan Jenne
8ab32a4d2b Jobs: Fix references 2023-11-15 15:13:53 +01:00
Jonathan Jenne
130281b602 Add References UML 2023-11-14 10:10:14 +01:00
Jonathan Jenne
02272f980f Add PDFConverter 2023-11-14 10:10:05 +01:00
Jonathan Jenne
e402cdaf5c Remove Language 2023-10-13 11:07:55 +02:00
Jonathan Jenne
348d054e16 fix process file handling 2023-10-12 14:01:40 +02:00
Jonathan Jenne
011b78472b einmal mit profis 2023-10-12 13:29:51 +02:00
Jonathan Jenne
4f3d8e0c7d Fix zugferd count in process files 2023-10-12 13:06:10 +02:00
Jonathan Jenne
7b01ef788a check for missing mailsession 2023-10-11 15:35:04 +02:00
Jonathan Jenne
a64823ae5e Zugferd: fix 2023-10-10 15:53:55 +02:00
Jonathan Jenne
c187bdbe5e Refactor: Processfiles 2023-10-09 16:05:50 +02:00
Jonathan Jenne
3c149a32e9 Config: Version 1.2.2.0 2023-10-04 13:59:16 +02:00
Jonathan Jenne
2153e83426 fix 2023-10-04 13:58:26 +02:00
Jonathan Jenne
278dda42a8 fix 2023-10-04 13:41:12 +02:00
Jonathan Jenne
1556f8bc45 fix 2023-10-04 13:40:09 +02:00
Jonathan Jenne
b3b3e80509 fix ConfigUtils 2023-10-04 13:39:13 +02:00
Jonathan Jenne
441f65915f Config: improve config migration 2023-10-04 13:21:03 +02:00
Jonathan Jenne
aa27dd8c1c Interfaces/Zugferd: fix missing regex group 2023-09-29 13:15:31 +02:00
Jonathan Jenne
20ec64c21d BAse: add missing constants 2023-09-29 13:15:00 +02:00
Jonathan Jenne
7a6537d529 Config: add MigrateAppConfig 2023-09-29 13:14:39 +02:00
Jonathan Jenne
e2d67ab6d7 Logging: Version 2.6.3.0 2023-09-18 09:21:07 +02:00
Jonathan Jenne
79e10ef2f6 Logging: Remove obsolete log target 2023-09-18 09:20:57 +02:00
Jonathan Jenne
da8ba360ca ZUGFERD: 2.1.0.0 2023-09-18 09:20:42 +02:00
Jonathan Jenne
fac8762888 ZUGFERD: Fix GetMessageIdFromFileName to work with new Email Profiler filenames 2023-09-18 09:19:08 +02:00
Jonathan Jenne
ddffb9c4f8 Messaging: Rework mail fetcher to build client adhoc 2023-09-15 09:24:48 +02:00
Jonathan Jenne
b16050cfc6 Database: fix missing message on exception 2023-09-14 15:40:45 +02:00
Jonathan Jenne
a415f90906 Messaging: Fix Mail Session 2023-09-14 15:40:23 +02:00
Jonathan Jenne
e8974376c5 Messaging: First working version of OAuth2 2023-09-06 10:24:46 +02:00
Jonathan Jenne
6f33261101 Fix filesystem refs 2023-09-05 10:47:37 +02:00
Jonathan Jenne
af90bb9efe Add Base.Test, Remove Filesystem 2023-09-05 10:37:52 +02:00
Jonathan Jenne
e12b087c94 Base: Add Filesystem Classes 2023-09-05 10:37:19 +02:00
Jonathan Jenne
3cb625c921 Filesystem: remove project 2023-09-05 10:37:02 +02:00
Jonathan Jenne
70bb33f823 Base: move Files 2023-09-05 10:25:49 +02:00
Jonathan Jenne
e63d1ea557 Logging: Improve json logging 2023-09-01 13:56:37 +02:00
Jonathan Jenne
2b80e8fa97 Jobs: Remove obsolete history function 2023-09-01 13:56:12 +02:00
Jonathan Jenne
9cab65f941 Jobs: Prepare Service Refactor, fix nullref error with emaildata, remove obsolete loops 2023-09-01 13:55:55 +02:00
Jonathan Jenne
4c8bdb27fd Jobs: add filename property MD5HashException, Add meaningful message to MissingValueException 2023-09-01 13:44:00 +02:00
Jonathan Jenne
b604ffcba2 Jobs: Only support one watch directory 2023-09-01 13:43:19 +02:00
Jonathan Jenne
6ef1e97deb Jobs: Add filename placeholder to EMAIL_MD5_ERROR 2023-09-01 13:42:53 +02:00
Jonathan Jenne
60bcf26379 Jobs: Add default Values to email data 2023-09-01 13:42:26 +02:00
Jonathan Jenne
a4a3dc4536 Restructure Base 2023-09-01 13:41:40 +02:00
Jonathan Jenne
86d61e720f Base: Version 1.3.5.0 2023-08-22 08:40:09 +02:00
Jonathan Jenne
002931d6dd Filesystem: Version 1.5.2.0 2023-08-22 08:39:40 +02:00
Jonathan Jenne
77d8a0825f Messaging: WIP MailFetcher, MailSession 2023-08-22 08:38:46 +02:00
Jonathan Jenne
f6046aec54 Base: migrate functions from other modules, add new functions 2023-08-22 08:38:21 +02:00
Jonathan Jenne
72f7211d63 Jobs/Zugferd: Improve structure 2023-08-22 08:37:15 +02:00
Jonathan Jenne
7fea3dc1ff Fix GetVersionedFileName 2023-08-22 08:35:47 +02:00
Jonathan Jenne
ec309b5afb Database: Version 2.3.3.2 2023-07-31 14:25:02 +02:00
Jonathan Jenne
681c561a7d add property MaskedConnectionString 2023-07-31 14:24:47 +02:00
Jonathan Jenne
22a30533c2 Base: Version 1.3.4.0 2023-07-27 16:11:17 +02:00
Jonathan Jenne
de418bcca4 Base: add drawrectangle, getshorthash 2023-07-27 16:10:49 +02:00
Jonathan Jenne
7b2b37a870 Base: Add WindowsEx, ScreenEx 2023-07-27 15:47:02 +02:00
Jonathan Jenne
28538bcf41 Fix references to Firebird tables 2023-07-27 15:46:30 +02:00
Jonathan Jenne
d73fa2a1c5 Jobs: Version 2.0.0.0 2023-07-25 15:27:17 +02:00
Jonathan Jenne
2288bc3fb9 Jobs/ZUGFeRD: Remove Firebird Database 2023-07-25 15:26:41 +02:00
Jonathan Jenne
05a590b169 Patterns: Add warning when control was not found 2023-07-24 10:43:55 +02:00
Jonathan Jenne
03f81938ae Fix connection mismatch for getdatatable / getscalarvalue 2023-07-24 10:43:11 +02:00
Jonathan Jenne
89ee1caf36 Base: Version 1.3.3.0 2023-07-24 10:42:04 +02:00
Jonathan Jenne
73f95de4c8 Base: handle non-existing column in NotNull 2023-07-24 10:41:36 +02:00
Jonathan Jenne
5ec049ff61 add mime type checks 2023-07-24 10:33:45 +02:00
Jonathan Jenne
56b0fedbe2 Jobs: Fix typo in EmailStrings 2023-06-27 09:21:51 +02:00
Jonathan Jenne
902231ff86 Base: Version 1.3.2.0 2023-06-26 16:33:55 +02:00
Jonathan Jenne
e5b5c259d7 Base: Add ToURLQueryString function for dictionay 2023-06-26 16:33:36 +02:00
Jonathan Jenne
c5b6498f1b Jobs: Version 1.15.1.0 2023-06-26 16:32:09 +02:00
Jonathan Jenne
39a406bfaf Fix incorrect error message with more than one valid zugferd invoice 2023-06-26 14:50:07 +02:00
Jonathan Jenne
222176dfca Jobs: Version 1.15.0.0 2023-06-22 10:53:08 +02:00
Jonathan Jenne
2517db3d68 Interfaces: Version 1.12.0.0 2023-06-22 10:53:00 +02:00
Jonathan Jenne
c9437f4a5c Database: Remove TableCache 2023-06-22 10:51:52 +02:00
Jonathan Jenne
524c429de4 ZUGFeRD: Validate errors in xml and throw ValidationException 2023-06-22 10:51:43 +02:00
Jonathan Jenne
0da1eb55a9 Interfaces: Version 1.11.0.0 2023-06-21 13:10:16 +02:00
Jonathan Jenne
18b0d4cdaf Jobs: Fix zugferd email string typo 2023-06-21 13:09:32 +02:00
Jonathan Jenne
a05156a1a6 Interfaces: Rewrite ValidateZugferdDocument, add validation for invalid decimals 2023-06-21 13:09:11 +02:00
Jonathan Jenne
a19123dd03 Base: Version 1.3.1.0 2023-06-16 11:23:59 +02:00
Jonathan Jenne
1c5cc2e6fc Base: fix typo 2023-06-16 11:23:52 +02:00
Jonathan Jenne
7625f2d2e3 Base: fix typo 2023-06-16 10:35:14 +02:00
Jonathan Jenne
f2e275c8bd Base: add RetoreWindowSize 2023-06-16 10:32:50 +02:00
Jonathan Jenne
e156cc9d88 Interfaces: 1.10.5.1 2023-06-16 09:21:42 +02:00
Jonathan Jenne
cfef91059a Filesystem: 1.5.1.1 2023-06-16 09:21:08 +02:00
Jonathan Jenne
a4916ba25f EDMIAPI: Version 1.6.1.1 2023-06-16 09:20:48 +02:00
Jonathan Jenne
18374ba93d Database: Version 2.3.3.1 2023-06-16 09:20:23 +02:00
Jonathan Jenne
977f79b6a6 Base: Version 1.3.0.0 2023-06-16 09:20:01 +02:00
Jonathan Jenne
8c1a1af140 edmiapi: Improve error logging 2023-06-16 09:19:24 +02:00
Jonathan Jenne
36b38f0bd8 database: improve error loggging 2023-06-16 09:19:10 +02:00
Jonathan Jenne
c9c56ad720 Interfaces: Improve error logging 2023-06-16 09:18:48 +02:00
Jonathan Jenne
ab280ccabe File: attempt to fix GetVersionedFilenameWithFilecheck 2023-06-16 09:18:10 +02:00
Jonathan Jenne
b1114545a7 Add a lot of functions to Base 2023-06-16 09:16:49 +02:00
Jonathan Jenne
00cff028c9 Base: Add ScreenEx 2023-05-26 15:05:00 +02:00
Jonathan Jenne
76cba215fe Interfaces/Job: Add check for currencyId format in ZUGFeRD documents 2023-05-26 15:04:44 +02:00
Jonathan Jenne
f491d4dd24 Language: Add comments 2023-05-23 12:04:31 +02:00
Jonathan Jenne
e65a6fa1a4 Filesystem: Add GetHash / GetHashFromString methods 2023-05-23 12:04:10 +02:00
Jonathan Jenne
726bdd1b2d Base: Version 1.2.1.0 2023-05-23 12:03:38 +02:00
Jonathan Jenne
fd2ad3f056 Base: Rename classes 2023-05-23 12:03:22 +02:00
Jonathan Jenne
a856f5f1b3 Database: Version 2.3.3.0 2023-05-16 08:48:03 +02:00
Jonathan Jenne
5ced396e3f Base: Version 1.2.0.0 2023-05-16 08:47:35 +02:00
Jonathan Jenne
10d8e7749a Database: Fix Logging of errors with sql queries 2023-05-16 08:47:24 +02:00
Jonathan Jenne
cd3646dca0 Base: Add Language Module 2023-05-15 16:02:39 +02:00
0c1b070a90 Currency Wrapper windream 2023-04-26 15:18:11 +02:00
da9dd6dcd7 MS 2023-04-25 17:14:41 +02:00
dd4a4aad95 MS 2023-04-25 13:24:16 +02:00
Jonathan Jenne
98fd711ea0 Windream: Version 1.9.2.0 2023-04-11 10:05:42 +02:00
Jonathan Jenne
0008d0f3ba Use windream filecheck for VersionWMFilename 2023-04-11 10:05:28 +02:00
Jonathan Jenne
fb2e8a6f6c Filesystem: Version 1.5.1 2023-04-03 16:33:41 +02:00
Jonathan Jenne
2d2c09bdf4 Filesystem: restrict getversionedfilename to 100 tries 2023-04-03 16:33:14 +02:00
Jonathan Jenne
1c49054844 Add logging 2023-03-30 15:34:35 +02:00
Jonathan Jenne
c871b06cc2 EDMI.API: Version 1.6.1.0 2023-03-30 12:00:25 +02:00
Jonathan Jenne
1a860c9270 EDMI.API: DatabaseWithFallback does not use connection in some circumstances 2023-03-30 12:00:07 +02:00
Jonathan Jenne
88ac9e70b2 Windream: Version 1.9.1.0 2023-03-28 13:43:46 +02:00
Jonathan Jenne
6885bd2954 Windream: Handle unc paths in NormalizePath 2023-03-28 13:43:33 +02:00
Jonathan Jenne
4a221a9e1d Version 1.10.5.0 2023-03-02 14:21:00 +01:00
Jonathan Jenne
11ab322138 Interfaces/Zugferd: Fix errors in Zugferd 2.1.1 Schema 2023-03-02 14:20:26 +01:00
Jonathan Jenne
9cea30235d Interfaces: Version 1.10.4.0 2023-02-28 14:56:39 +01:00
Jonathan Jenne
f3afadc3b7 Interfaces: fix Zugferd exceptions 2023-02-28 14:56:01 +01:00
Jonathan Jenne
89fbc4e4ae Interfaces: Version 1.10.3.0 2023-02-28 14:12:56 +01:00
Jonathan Jenne
adf692629a Interfaces: Improve logging 2023-02-28 14:12:28 +01:00
Jonathan Jenne
f6f421ddd8 Interfaces: Version 1.10.2.0 2023-02-28 13:50:17 +01:00
Jonathan Jenne
2ced2f192f Jobs: Version 1.14.1.0 2023-02-28 13:50:03 +01:00
Jonathan Jenne
a80b943dc5 Interfaces/Jobs: add new method FilterPropertyMap 2023-02-28 13:49:16 +01:00
Jonathan Jenne
214edf22a5 Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2023-02-28 11:42:55 +01:00
Jonathan Jenne
5ac3aaab54 Jobs: Version 1.14.0.0 2023-02-28 11:42:49 +01:00
Jonathan Jenne
1ab246fc46 Jobs/ZUGFeRD: Write Zugferd Specification to database 2023-02-28 11:42:20 +01:00
Jonathan Jenne
9fe177abd3 Interfaces: Add FileTooBig Error, Add note about future refactoring of GetPropertyValue 2023-02-23 16:23:26 +01:00
ed7aea5b72 Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2023-02-22 12:03:53 +01:00
8e1c459a61 MS Config OverrideLang 2023-02-22 12:03:41 +01:00
Jonathan Jenne
f6acae9185 Language: Version 1.7.1 2023-02-22 11:07:43 +01:00
Jonathan Jenne
fd0876a1cb Language: Add FieldOrDefault method 2023-02-22 11:07:34 +01:00
Jonathan Jenne
ad5443adae Filesystem: fix typo 2023-02-02 13:30:37 +01:00
Jonathan Jenne
39a0c8b8ec Jobs: Version 1.13.0.0 2023-02-02 13:13:12 +01:00
Jonathan Jenne
46ce5342a0 Filesystem: Version 1.5.0 2023-02-02 13:12:41 +01:00
Jonathan Jenne
1013dd3c30 Jobs: Use TestFileSizeIsLessThanMaxFileSize 2023-02-02 13:11:41 +01:00
Jonathan Jenne
41bba8b214 Filesystem: Add TestFileSizeIsLessThanMaxFileSize 2023-02-02 13:11:16 +01:00
Jonathan Jenne
4ee519d8c6 Messaging: Remove Tls13 setting 2023-01-24 14:43:26 +01:00
Jonathan Jenne
d9690d270b Downgrade to 4.6.2 2023-01-24 14:35:09 +01:00
Jonathan Jenne
1c86b8091b Messaging: version 1.9.1 2023-01-23 09:27:59 +01:00
Jonathan Jenne
8738fd8300 Messaging: Make tls version configurable 2023-01-23 09:27:52 +01:00
Jonathan Jenne
27e3462b6e Jobs: Version 1.12.1.0 2023-01-12 14:37:50 +01:00
Jonathan Jenne
1d0688e995 Interfaces: Version 1.10.1.0 2023-01-12 14:37:39 +01:00
Jonathan Jenne
c1018d176e ZUGFeRD: Update for new version 2023-01-12 14:33:54 +01:00
3183b0ed31 MS 2023-01-03 16:03:51 +01:00
b33720c61e MS 2023-01-03 16:03:15 +01:00
Jonathan Jenne
baa661cb14 Jobs: Version 1.12.0.1 2022-12-23 13:29:46 +01:00
Jonathan Jenne
e5ec777d61 Jobs: Fix typo in importzugferdfiles 2022-12-23 13:29:01 +01:00
Jonathan Jenne
4dfe32ba33 Jobs: Fix typo in EmailStrings 2022-12-23 13:28:41 +01:00
Jonathan Jenne
65d58a2274 Zugferd: prepare loading different specs per document schema version 2022-12-21 14:02:44 +01:00
Jonathan Jenne
902c835c37 Jobs/zugferd: add fallback for missing values in GetEmailDataForMessageId 2022-12-21 10:17:31 +01:00
Jonathan Jenne
79cad24b3f Interfaces/zugferd: fix parameter error which leads to falsely allowing mails with two zugferd invoices 2022-12-21 10:16:50 +01:00
Jonathan Jenne
a9567a9d18 Jobs/zugferd: Include subject in rejection messages 2022-12-21 10:14:19 +01:00
Jonathan Jenne
0d207a25a5 Logging: Version 2.6.2.0 2022-12-16 13:52:43 +01:00
Jonathan Jenne
19f33dbb2c Fix json target 2022-12-16 13:52:33 +01:00
Jonathan Jenne
0ed5a164e8 Interfaces: Version 1.10.0.0 2022-12-16 09:30:52 +01:00
Jonathan Jenne
36dd27b26c Jobs: Version 1.12.0.0 2022-12-16 09:30:10 +01:00
Jonathan Jenne
3df54fa62c Jobs/Interfaces: add options for enabling / disabling zugferd schemas 2022-12-16 09:29:34 +01:00
Jonathan Jenne
67cdc580fa Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2022-12-16 09:08:42 +01:00
Jonathan Jenne
c082222c80 Messaging: Add binding class 2022-12-16 09:04:14 +01:00
Jonathan Jenne
33a95ba46d Version 2.6.1.0 2022-12-16 09:03:41 +01:00
Jonathan Jenne
a00ad5a9c0 Logging: WIP Json logging 2022-12-16 09:03:21 +01:00
Jonathan Jenne
db1d3fb197 Interfaces: Version 1.9.1.0 2022-12-16 08:37:29 +01:00
Jonathan Jenne
d5e98c5de4 Interfaces: Prepare language attribute in ADUser 2022-12-16 08:36:56 +01:00
Jonathan Jenne
e717dffa54 Filesystem: Version 1.4.1.0 2022-12-16 08:35:37 +01:00
Jonathan Jenne
eae009e82d Filesystem: Add new method GetVersionedFilenameWithFileCheck 2022-12-16 08:35:06 +01:00
Jonathan Jenne
d74e0f304a Database: Version 2.3.1.0 2022-12-16 08:34:33 +01:00
Jonathan Jenne
2816b644da Database: Log all command parameters 2022-12-16 08:34:19 +01:00
Jonathan Jenne
b927e07141 Windream: Version 1.7.1 2022-12-16 08:33:39 +01:00
Jonathan Jenne
f5107a3d21 Windream: Fix normalized paths 2022-12-16 08:33:09 +01:00
75df258abf Ms 2022-12-15 15:57:50 +01:00
Jonathan Jenne
1ea73d9234 Windream: improve logging 2022-12-09 13:40:10 +01:00
Jonathan Jenne
d44ab2f087 Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2022-12-09 13:31:08 +01:00
Jonathan Jenne
bd6d483867 Windream: Fix NewFolder 2022-12-09 13:31:01 +01:00
7b7b17b657 MS Push Windream 2022-12-09 13:30:44 +01:00
Jonathan Jenne
3883c0dad7 Messaging: Add general WCF code 2022-11-30 09:34:26 +01:00
Jonathan Jenne
078282c579 ZooFlow: Update to Nlog 5 - Version 1.3.0.0 2022-11-25 13:07:32 +01:00
Jonathan Jenne
e91af7de7c Windream: Update to Nlog 5 - Version 1.7.0.0 2022-11-25 13:06:23 +01:00
Jonathan Jenne
fb5527036a Windows: Update to Nlog 5 - Version 1.5.0.0 2022-11-25 13:05:44 +01:00
Jonathan Jenne
211c394b2f Patterns: Update to Nlog 5 - Version 1.3.0.0 2022-11-25 13:05:11 +01:00
Jonathan Jenne
5f52434d67 Messaging: Update to Nlog 5 - Version 1.8.0.0 2022-11-25 13:04:38 +01:00
Jonathan Jenne
e2494e5117 Logging: Update to Nlog 5 - Version 2.6.0.0 2022-11-25 13:03:58 +01:00
Jonathan Jenne
dd5a1c0766 License: Update to Nlog 5 - Version 1.1.0.0 2022-11-25 13:03:02 +01:00
Jonathan Jenne
a69fecd75d Language: Update to Nlog 5 - Version 1.7.0.0 2022-11-25 13:01:54 +01:00
Jonathan Jenne
7b249fb9cb Jobs: Update to Nlog 5 - Version 1.11.0.0 2022-11-25 13:01:12 +01:00
Jonathan Jenne
c5973c86c9 Interfaces: Update to Nlog 5 - Version 1.9.0.0 2022-11-25 13:00:27 +01:00
Jonathan Jenne
680b496b90 Filesystem: Update to Nlog 5 - Version 1.4.0.0 2022-11-25 12:59:51 +01:00
Jonathan Jenne
c9ef17e533 Encryption: Update to Nlog 5 - Version 1.2.0.0 2022-11-25 12:59:05 +01:00
Jonathan Jenne
780238625c EDMI.API: Update to Nlog 5 - Version 1.6.0.0 2022-11-25 12:57:18 +01:00
Jonathan Jenne
5794018c5e Database: Update to Nlog 5 - Version 2.3.0.0 2022-11-25 12:56:42 +01:00
Jonathan Jenne
b329492521 Config: Update to Nlog 5 - Version 1.2.0.0 2022-11-25 12:56:24 +01:00
Jonathan Jenne
22b3918a03 Base: Update to Nlog 5 - Version 1.1.0.0 2022-11-25 12:56:10 +01:00
Jonathan Jenne
15d6cac420 Logging: write log when debug flag is changed 2022-11-25 12:09:41 +01:00
Jonathan Jenne
a469ff9a23 1.10.0.4 2022-11-25 11:33:10 +01:00
Jonathan Jenne
55fc875d3a Jobs/GraphQL: Actually insert the status value 2022-11-25 11:28:35 +01:00
Jonathan Jenne
1d04027c5f Jobs: Version 1.10.0.3 2022-11-25 11:05:06 +01:00
Jonathan Jenne
e3c500938b Jobs: fix typo, use truncate instead of delete 2022-11-25 11:04:36 +01:00
Jonathan Jenne
dbbacd2623 Jobs: Version 1.10.0.2 2022-11-25 10:56:30 +01:00
Jonathan Jenne
7d86d583de Jobs: Fix typo 2022-11-25 10:56:07 +01:00
Jonathan Jenne
5c4b302aa7 Jobs: Version 1.10.0.1 2022-11-25 10:29:51 +01:00
Jonathan Jenne
1d8a0faeee Database: Version 2.2.7.6 2022-11-25 10:29:18 +01:00
Jonathan Jenne
ca92abbee5 Jobs: WIP GraphQL Job, fix logic errors, improve logging 2022-11-25 10:28:52 +01:00
Jonathan Jenne
8267ecb72d Database: Fix logging 2022-11-25 10:28:20 +01:00
Jonathan Jenne
86ca1011df Jobs: Version 1.10.0.0 2022-11-24 14:28:39 +01:00
Jonathan Jenne
b1aba0a80d Jobs: Add exception for unsupported zugferd documents 2022-11-24 14:26:42 +01:00
Jonathan Jenne
a8862709d8 Jobs: Update to use Job Runner Table 2022-11-24 14:24:59 +01:00
Jonathan Jenne
36fe39ee66 Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2022-11-24 11:24:37 +01:00
Jonathan Jenne
ddc11b62a5 Database: Small stuff 2022-11-24 11:24:26 +01:00
Jonathan Jenne
7ba516fcd1 Interfaces: Version 1.8.1.0 2022-11-24 11:20:31 +01:00
Jonathan Jenne
05a92c3181 Language: Version 1.6.2.0 2022-11-24 11:20:00 +01:00
Jonathan Jenne
7d63718e96 Interfaces/ActiveDirectory: Improve logging 2022-11-24 11:19:22 +01:00
Jonathan Jenne
8af67ef883 Language: Improve StringEx 2022-11-24 11:14:20 +01:00
6ed636bca0 Merge branch 'master' of http://git.dd:3000/AppStd/Modules 2022-11-17 17:09:16 +01:00
5f8e1a8608 MS windream Mod 2022-11-17 17:09:07 +01:00
Jonathan Jenne
e424402d63 Interfaces: Version 1.8.0.0 2022-11-16 16:34:46 +01:00
Jonathan Jenne
9d6dd695e4 Jobs: 1.9.0.0 2022-11-16 16:34:10 +01:00
Jonathan Jenne
0410e11b59 ZUGFeRD: WIP Allow blocking factur-x and xrechnung invoice files with config flags 2022-11-16 16:33:35 +01:00
Jonathan Jenne
f4adba98eb Interfaces: Version 1.7.5.0 2022-11-14 11:46:08 +01:00
Jonathan Jenne
1dba028deb Interfaces: Add errortype unknownerror 2022-11-14 11:45:20 +01:00
Jonathan Jenne
3a26343083 Merge branch 'Database_SqlConnection' 2022-11-02 16:20:43 +01:00
Jonathan Jenne
1e732a036a Revert all modules to .NET 4.6.1 2022-11-02 14:35:43 +01:00
Jonathan Jenne
41165a470d Language: Version 1.6.1.0 2022-11-02 13:36:52 +01:00
Jonathan Jenne
8128987be4 Language: Add EscapeForSQL string extension method 2022-11-02 13:36:29 +01:00
Jonathan Jenne
6ebd3b82b6 Messaging: Improve logging 2022-11-02 13:36:00 +01:00
Jonathan Jenne
d18ebfe912 Jobs: 1.8.7.0 2022-11-02 13:35:04 +01:00
Jonathan Jenne
b614b3f140 Jobs: escape attachment paths 2022-11-02 13:34:33 +01:00
197 changed files with 6010 additions and 5177 deletions

View File

@@ -10,7 +10,7 @@
<AssemblyName>DigitalData.Modules.Base</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
@@ -46,16 +46,19 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -74,11 +77,25 @@
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseClass.vb" />
<Compile Include="ECM\ECM.vb" />
<Compile Include="IDB\Attributes.vb" />
<Compile Include="IDB\Database.vb" />
<Compile Include="IDB\FileStore.vb" />
<Compile Include="Base\BaseClass.vb" />
<Compile Include="Base\BaseUtils.vb" />
<Compile Include="Encryption\Compression.vb" />
<Compile Include="Encryption\Encryption.vb" />
<Compile Include="Encryption\EncryptionLegacy.vb" />
<Compile Include="DatabaseEx.vb" />
<Compile Include="FilesystemEx.vb" />
<Compile Include="FileWatcher\FileWatcher.vb" />
<Compile Include="FileWatcher\FileWatcherFilters.vb" />
<Compile Include="FileWatcher\FileWatcherProperties.vb" />
<Compile Include="IDB\Constants.vb" />
<Compile Include="MimeEx.vb" />
<Compile Include="WindowsEx.vb" />
<Compile Include="ModuleExtensions.vb" />
<Compile Include="FileEx.vb" />
<Compile Include="NativeMethods.vb" />
<Compile Include="ObjectEx.vb" />
<Compile Include="GraphicsEx.vb" />
<Compile Include="LanguageEx.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
@@ -95,7 +112,8 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Performance.vb" />
<Compile Include="ScreenEx.vb" />
<Compile Include="StringEx.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">
@@ -126,5 +144,6 @@
<Name>Logging</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>

7
Base/Base/BaseUtils.vb Normal file
View File

@@ -0,0 +1,7 @@
Friend Class BaseUtils
Friend Shared Function FormatHash(pChecksum)
Return BitConverter.
ToString(pChecksum).
Replace("-", String.Empty)
End Function
End Class

17
Base/DatabaseEx.vb Normal file
View File

@@ -0,0 +1,17 @@
Public Class DatabaseEx
''' <summary>
''' TODO: Deprecate
''' Checks a Row value for three different `null` values,
''' Nothing, Empty String, DBNull
'''
''' Returns the original value if the value is not null, or `defaultValue`
''' </summary>
''' <typeparam name="T">The type of the value</typeparam>
''' <param name="pRow">The DataRow that contains the value</param>
''' <param name="pColumn">The column name</param>
''' <param name="pDefaultValue">The default value</param>
''' <returns>The original value or the default value</returns>
Public Shared Function NotNull(Of T)(ByVal pRow As DataRow, pColumn As String, pDefaultValue As T) As T
Return ObjectEx.NotNull(pRow.Item(pColumn), pDefaultValue)
End Function
End Class

View File

@@ -1,7 +0,0 @@
Public Class ECM
Public Enum Product
ProcessManager
GlobalIndexer
ClipboardWatcher
End Enum
End Class

View File

@@ -0,0 +1,70 @@
Imports System.IO
Imports System.IO.Compression
Imports DigitalData.Modules.Logging
Public Class Compression
Private ReadOnly _logger As Logger
Public Sub New(LogConfig As LogConfig)
_logger = LogConfig.GetLogger()
End Sub
Public Async Function CompressAsync(data As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Compress(data)
End Function)
End Function
Public Function Compress(data As Byte()) As Byte()
Try
' ByteArray in Stream umwandeln
Using originalStream As New MemoryStream(data)
' Ziel Stream erstellen
Using compressedStream As New MemoryStream()
' Gzip-Stream erstellen, der alle Daten komprimiert und zu compressedStream durchleitet
'
' > MemoryStream > GzipStream > MemoryStream
' originalStream --> compressionStream --> compressedFileStream
'
Using compressionStream As New GZipStream(compressedStream, CompressionMode.Compress)
originalStream.CopyTo(compressionStream)
compressionStream.Close()
Return compressedStream.ToArray()
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function DecompressAsync(data As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Decompress(data)
End Function)
End Function
Public Function Decompress(data As Byte()) As Byte()
Try
' ByteArray in Stream umwandeln
Using compressedStream As New MemoryStream(data)
' Ziel Stream erstellen
Using decompressedStream As New MemoryStream()
' Gzip-Stream erstellen, der alle Daten komprimiert und zu compressedStream durchleitet
'
' > MemoryStream > GzipStream > MemoryStream
' compressedStream --> decompressionStream --> decompressedStream
'
Using decompressionStream As New GZipStream(compressedStream, CompressionMode.Decompress)
decompressionStream.CopyTo(decompressedStream)
Return decompressedStream.ToArray()
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
End Class

View File

@@ -0,0 +1,148 @@
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text.Encoding
Imports DigitalData.Modules.Logging
''' <summary>
''' https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp
''' </summary>
Public Class Encryption
' This constant is used to determine the keysize of the encryption algorithm in bits.
' We divide this by 8 within the code below to get the equivalent number of bytes.
Private Const KEY_SIZE As Integer = 256
' This constant determines the number of iterations for the password bytes generation function.
Private Const DERIVATION_ITERATIONS As Integer = 1000
Private Const BLOCK_SIZE As Integer = 256
Private _paddingMode As PaddingMode = PaddingMode.Zeros
Private _cipherMode As CipherMode = CipherMode.CBC
Private ReadOnly _password As String
Private _logger As Logger
Public Sub New(LogConfig As LogConfig, Password As String)
_logger = LogConfig.GetLogger()
If IsNothing(Password) Then
Throw New ArgumentNullException("Password")
End If
_password = Password
End Sub
Public Async Function EncryptAsync(PlainTextBytes As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Encrypt(PlainTextBytes)
End Function)
End Function
Public Function Encrypt(PlainText As String) As String
Try
Dim oBytes As Byte() = UTF8.GetBytes(PlainText)
Dim oEncrypted As Byte() = Encrypt(oBytes)
Return UTF8.GetString(oEncrypted)
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function Encrypt(PlainTextBytes As Byte()) As Byte()
Try
' Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
' so that the same Salt and IV values can be used when decrypting.
Dim oSaltStringBytes = Generate256BitsOfRandomEntropy()
Dim oIvStringBytes = Generate256BitsOfRandomEntropy()
Using oPassword = New Rfc2898DeriveBytes(_password, oSaltStringBytes, DERIVATION_ITERATIONS)
Dim oKeyBytes = oPassword.GetBytes(KEY_SIZE / 8)
Using oSymmetricKey = New RijndaelManaged()
oSymmetricKey.BlockSize = BLOCK_SIZE
oSymmetricKey.Mode = _cipherMode
oSymmetricKey.Padding = _paddingMode
Using oEncryptor = oSymmetricKey.CreateEncryptor(oKeyBytes, oIvStringBytes)
Using oMemoryStream = New MemoryStream()
Using oCryptoStream = New CryptoStream(oMemoryStream, oEncryptor, CryptoStreamMode.Write)
oCryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length)
oCryptoStream.FlushFinalBlock()
' Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
Dim oCipherTextBytes = oSaltStringBytes
oCipherTextBytes = oCipherTextBytes.Concat(oIvStringBytes).ToArray()
oCipherTextBytes = oCipherTextBytes.Concat(oMemoryStream.ToArray()).ToArray()
oMemoryStream.Close()
oCryptoStream.Close()
Return oCipherTextBytes
End Using
End Using
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function DecryptAsync(CipherTextBytesWithSaltAndIv As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Decrypt(CipherTextBytesWithSaltAndIv)
End Function)
End Function
Public Function Decrypt(CipherTextPlainWithSaltAndIv As String) As String
Try
Dim oBytes As Byte() = UTF8.GetBytes(CipherTextPlainWithSaltAndIv)
Dim oDecrypted As Byte() = Decrypt(oBytes)
Return UTF8.GetString(oDecrypted)
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function Decrypt(CipherTextBytesWithSaltAndIv As Byte()) As Byte()
Try
' Get the complete stream of bytes that represent:
' [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
' Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
Dim oSaltStringBytes = CipherTextBytesWithSaltAndIv.Take(KEY_SIZE / 8).ToArray()
' Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
Dim oIvStringBytes = CipherTextBytesWithSaltAndIv.Skip(KEY_SIZE / 8).Take(KEY_SIZE / 8).ToArray()
' Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
Dim oCipherTextBytes = CipherTextBytesWithSaltAndIv.Skip((KEY_SIZE / 8) * 2).Take(CipherTextBytesWithSaltAndIv.Length - ((KEY_SIZE / 8) * 2)).ToArray()
Using oPassword = New Rfc2898DeriveBytes(_password, oSaltStringBytes, DERIVATION_ITERATIONS)
Dim oKeyBytes = oPassword.GetBytes(KEY_SIZE / 8)
Using oSymmetricKey = New RijndaelManaged()
oSymmetricKey.BlockSize = BLOCK_SIZE
oSymmetricKey.Mode = _cipherMode
oSymmetricKey.Padding = _paddingMode
Using oDecryptor = oSymmetricKey.CreateDecryptor(oKeyBytes, oIvStringBytes)
Using oMemoryStream = New MemoryStream(oCipherTextBytes)
Using oCryptoStream = New CryptoStream(oMemoryStream, oDecryptor, CryptoStreamMode.Read)
Dim oPlainTextBytes = New Byte(oCipherTextBytes.Length - 1) {}
Dim oDecryptedByteCount = oCryptoStream.Read(oPlainTextBytes, 0, oPlainTextBytes.Length)
oMemoryStream.Close()
oCryptoStream.Close()
Return oPlainTextBytes
End Using
End Using
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Shared Function Generate256BitsOfRandomEntropy() As Byte()
Dim oRandomBytes = New Byte(31) {}
' 32 Bytes will give us 256 bits.
Using oRNGCsp = New RNGCryptoServiceProvider()
' Fill the array with cryptographically secure random bytes.
oRNGCsp.GetBytes(oRandomBytes)
End Using
Return oRandomBytes
End Function
End Class

View File

@@ -0,0 +1,85 @@
Imports System.Security.Cryptography
Imports System.Data
Imports System.Data.SqlClient
Public Class EncryptionLegacy
Private TripleDes As New TripleDESCryptoServiceProvider
Private DEFAULT_KEY As String = "!35452didalog="
Private SALT_VALUE As String = "!Didalog35452Heuchelheim="
Sub New()
TripleDes.Key = TruncateHash(DEFAULT_KEY, TripleDes.KeySize \ 8)
TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
End Sub
Sub New(key As String)
' Initialize the crypto provider.
TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8)
TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
End Sub
Private Function TruncateHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim sha1 As New SHA1CryptoServiceProvider
' Hash the key.
Dim keyBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(key)
Dim hash() As Byte = sha1.ComputeHash(keyBytes)
' Truncate or pad the hash.
ReDim Preserve hash(length - 1)
Return hash
End Function
<DebuggerStepThrough>
Public Function EncryptData(ByVal plaintext As String) As String
Try
' Convert the plaintext string to a byte array.
Dim plaintextBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(SALT_VALUE & plaintext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the encoder to write to the stream.
Dim encStream As New CryptoStream(ms,
TripleDes.CreateEncryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
encStream.FlushFinalBlock()
' Convert the encrypted stream to a printable string.
Return Convert.ToBase64String(ms.ToArray)
Catch ex As Exception
Return plaintext
End Try
End Function
'Entschlüsselt die Zeichenfolge
<DebuggerStepThrough>
Public Function DecryptData(ByVal EncryptedText As String) As String
Try
' Convert the encrypted text string to a byte array.
Dim oEncryptedBytes() As Byte = Convert.FromBase64String(EncryptedText)
' Create the stream.
Dim oMemoryStream As New System.IO.MemoryStream
' Create the decoder to write to the stream.
Dim oCryptoStream As New CryptoStream(oMemoryStream,
TripleDes.CreateDecryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
oCryptoStream.Write(oEncryptedBytes, 0, oEncryptedBytes.Length)
oCryptoStream.FlushFinalBlock()
Dim oResult = System.Text.Encoding.Unicode.GetString(oMemoryStream.ToArray)
oResult = oResult.Replace(SALT_VALUE, "")
' Convert the plaintext stream to a string.
Return oResult
Catch ex As Exception
Return EncryptedText
End Try
End Function
End Class

78
Base/FileEx.vb Normal file
View File

@@ -0,0 +1,78 @@
Imports System.IO
Imports System.Security.Cryptography
Public Class FileEx
''' <summary>
''' Reads the file at `FilePath` and computes a SHA256 Hash from its contents
''' </summary>
''' <param name="pFilePath"></param>
''' <returns></returns>
Public Shared Function GetChecksumFromFileContents(pFilePath As String) As String
Try
Using oFileStream = IO.File.OpenRead(pFilePath)
Using oStream As New BufferedStream(oFileStream, 1200000)
Dim oChecksum() As Byte = SHA256.Create.ComputeHash(oStream)
Return BaseUtils.FormatHash(oChecksum)
End Using
End Using
Catch ex As Exception
Return Nothing
End Try
End Function
Public Shared Function GetHashFromFileContents(pFilePath As String) As String
Return GetChecksumFromFileContents(pFilePath)
End Function
''' <summary>
''' Returns a Dictionary path in the form of [Base]\[Year]\[Month]\[Day]
''' </summary>
''' <param name="pBaseDirectory">The basedirectory</param>
''' <param name="pDate">The date to be used</param>
''' <returns>The final directory path</returns>
Public Shared Function GetDateDirectory(pBaseDirectory As String, pDate As Date) As String
Dim oDateDirectory = StringEx.GetDateString(pDate)
Dim oFinalDirectory As String = Path.Combine(pBaseDirectory, oDateDirectory)
Return oFinalDirectory
End Function
''' <summary>
''' Returns a Dictionary path in the form of [Base]\[Year]\[Month]\[Day] based on the current date
''' </summary>
''' <param name="pBaseDirectory">The basedirectory</param>
''' <returns>The final directory path</returns>
Public Shared Function GetDateDirectory(pBaseDirectory As String) As String
Return GetDateDirectory(pBaseDirectory, Now)
End Function
''' <summary>
''' Creates a Dictionary in the form of [Base]\[Year]\[Month]\[Day]
''' </summary>
''' <param name="pBaseDirectory">The basedirectory</param>
''' <param name="pDate">The date to be used</param>
''' <returns>The created path. If the directory cannot be created, Nothing.</returns>
Public Shared Function CreateDateDirectory(pBaseDirectory As String, pDate As Date) As String
Dim oDateDirectory = StringEx.GetDateString(pDate)
Dim oFinalDirectory As String = Path.Combine(pBaseDirectory, oDateDirectory)
If Directory.Exists(oFinalDirectory) = False Then
Try
Directory.CreateDirectory(oFinalDirectory)
Catch ex As Exception
Return Nothing
End Try
End If
Return oFinalDirectory
End Function
''' <summary>
''' Creates a Dictionary in the form of [Base]\[Year]\[Month]\[Day] based on the current date
''' </summary>
''' <param name="pBaseDirectory">The basedirectory</param>
''' <returns>The created path. If the directory cannot be created, Nothing.</returns>
Public Shared Function CreateDateDirectory(pBaseDirectory As String) As String
Return CreateDateDirectory(pBaseDirectory, Now)
End Function
End Class

View File

@@ -1,6 +1,5 @@
Imports System.IO
Imports DigitalData.Modules.Filesystem
Imports DigitalData.Modules.Filesystem.FileWatcherFilters
Imports DigitalData.Modules.Base.FileWatcherFilters
Imports DigitalData.Modules.Logging

View File

@@ -1,29 +1,10 @@
Imports System.IO
Imports DigitalData.Modules.Logging
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Imports System.Text.RegularExpressions
Imports DigitalData.Modules.Logging
''' <module>File</module>
''' <version>0.0.0.1</version>
''' <date>11.10.2018</date>
''' <summary>
''' Module that provides variouse File operations
''' </summary>
''' <dependencies>
''' NLog, >= 4.5.8
''' </dependencies>
''' <params>
''' LogConfig, DigitalData.Module.Logging.LogConfig
''' A LogConfig object
''' </params>
''' <props>
''' </props>
''' <example>
''' </example>
''' <remarks>
''' </remarks>
Public Class File
Public Class FilesystemEx
Private ReadOnly _Logger As Logger
Private ReadOnly _LogConfig As LogConfig
@@ -39,6 +20,10 @@ Public Class File
' Source: https://docs.microsoft.com/de-de/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#maximum-path-length-limitation
Private Const MAX_FILE_PATH_LENGTH = 250
' This prevents an infinite loop when no file can be created in a location
Private Const MAX_FILE_VERSION = 100
Private Const VERSION_SEPARATOR As Char = "~"c
Private Const FILE_NAME_ACCESS_TEST = "accessTest.txt"
Public Sub New(LogConfig As LogConfig)
@@ -100,6 +85,14 @@ Public Class File
Return FormatHash(oChecksum)
End Function
Public Function GetHash(FilePath As String) As String
Return GetChecksum(FilePath)
End Function
Public Function GetHashFromString(pStringToCheck As String) As String
Return GetChecksumFromString(pStringToCheck)
End Function
Private Function FormatHash(pChecksum)
Return BitConverter.
ToString(pChecksum).
@@ -109,53 +102,65 @@ Public Class File
''' <summary>
''' Adds file version string to given filename `Destination` if that file already exists.
''' </summary>
''' <param name="Destination"></param>
''' <returns></returns>
Public Function GetVersionedFilename(Destination As String) As String
''' <param name="pFilePath">Filepath to check</param>
''' <returns>Versioned string</returns>
Public Function GetVersionedFilename(pFilePath As String) As String
Return GetVersionedFilenameWithFilecheck(pFilePath, Function(pPath As String) IO.File.Exists(pPath))
End Function
''' <summary>
''' Adds file version string to given filename `Destination` if that file already exists.
''' </summary>
''' <param name="pFilePath">Filepath to check</param>
''' <param name="pFileExistsAction">Custom action to check for file existence</param>
''' <returns>Versioned string</returns>
Public Function GetVersionedFilenameWithFilecheck(pFilePath As String, pFileExistsAction As Func(Of String, Boolean)) As String
Try
Dim oFileName As String = Destination
Dim oFileName As String = pFilePath
Dim oFinalFileName = oFileName
Dim oDestinationDir = Path.GetDirectoryName(oFileName)
Dim oExtension = Path.GetExtension(oFileName)
Dim oVersionSeparator As Char = "~"c
Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(oFileName)
Dim oSplitResult = GetVersionedString(oFileNameWithoutExtension, oVersionSeparator)
Dim oSplitResult = GetVersionedString(oFileNameWithoutExtension)
oFileNameWithoutExtension = oSplitResult.Item1
Dim oFileVersion = oSplitResult.Item2
Dim oFileVersion As Integer = oSplitResult.Item2
' Shorten the filename (only filename, without extension or version)
' by cutting the length in half. This should work no matter how long the path and/or filename are.
' The initial check operates on the full path to catch all scenarios.
If Destination.Length > MAX_FILE_PATH_LENGTH Then
If pFilePath.Length > MAX_FILE_PATH_LENGTH Then
_Logger.Info("Filename is too long. Filename will be cut to prevent further errors.")
_Logger.Info("Original Filename is: {0}", oFileNameWithoutExtension)
Dim oNewLength As Integer = Math.Round(oFileNameWithoutExtension.Length / 2)
Dim oNewLength As Integer = CInt(Math.Floor(oFileNameWithoutExtension.Length / 2.0))
Dim oNewFileNameWithoutExtension = oFileNameWithoutExtension.Substring(0, oNewLength)
_Logger.Info("New Filename will be: {0}", oNewFileNameWithoutExtension)
oFileNameWithoutExtension = oNewFileNameWithoutExtension
End If
' while file exists, increment version
' while file exists, increment version.
' version cannot go above MAX_FILE_VERSION, to prevent infinite loop
Do
oFinalFileName = Path.Combine(oDestinationDir, GetFilenameWithVersion(oFileNameWithoutExtension, oVersionSeparator, oFileVersion, oExtension))
oFinalFileName = Path.Combine(oDestinationDir, GetFilenameWithVersion(oFileNameWithoutExtension, oFileVersion, oExtension))
_Logger.Debug("Intermediate Filename is {0}", oFinalFileName)
_Logger.Debug("File version: {0}", oFileVersion)
oFileVersion += 1
Loop While (IO.File.Exists(oFinalFileName))
Loop While pFileExistsAction(oFinalFileName) = True And oFileVersion < MAX_FILE_VERSION
If oFileVersion >= MAX_FILE_VERSION Then
Throw New OverflowException($"Tried '{MAX_FILE_VERSION}' times to version filename before giving up. Sorry.")
End If
_Logger.Debug("Final Filename is {0}", oFinalFileName)
Return oFinalFileName
Catch ex As Exception
_Logger.Warn("Filename {0} could not be versioned. Original filename will be returned!", Destination)
_Logger.Warn("Filename {0} could not be versioned. Original filename will be returned!", pFilePath)
_Logger.Error(ex)
Return Destination
Return pFilePath
End Try
End Function
@@ -174,8 +179,8 @@ Public Class File
''' <param name="pString">The string to versioned</param>
''' <param name="pSeparator">The character to split at</param>
''' <returns>Tuple of string and version</returns>
Public Function GetVersionedString(pString As String, pSeparator As Char) As Tuple(Of String, Integer)
Dim oSplitString = pString.Split(pSeparator).ToList()
Public Function GetVersionedString(pString As String) As Tuple(Of String, Integer)
Dim oSplitString = pString.Split(VERSION_SEPARATOR).ToList()
Dim oStringVersion As Integer
' if string is already versioned, extract string version
@@ -195,6 +200,8 @@ Public Class File
oStringVersion = 1
End If
_Logger.Debug("Versioned: String [{0}], Version [{1}]", pString, oStringVersion)
Return New Tuple(Of String, Integer)(pString, oStringVersion)
End Function
@@ -203,11 +210,11 @@ Public Class File
Return Path.Combine(oLocalAppData, CompanyName, ProductName)
End Function
Private Function GetFilenameWithVersion(FileNameWithoutExtension As String, VersionSeparator As Char, FileVersion As Integer, Extension As String) As String
Private Function GetFilenameWithVersion(FileNameWithoutExtension As String, FileVersion As Integer, Extension As String) As String
If FileVersion <= 1 Then
Return $"{FileNameWithoutExtension}{Extension}"
Else
Return $"{FileNameWithoutExtension}{VersionSeparator}{FileVersion}{Extension}"
Return $"{FileNameWithoutExtension}{VERSION_SEPARATOR}{FileVersion}{Extension}"
End If
End Function
@@ -290,7 +297,7 @@ Public Class File
''' <param name="DestDirName"></param>
''' <param name="CopySubDirs"></param>
Public Sub CopyDirectory(ByVal SourceDirName As String, ByVal DestDirName As String, ByVal CopySubDirs As Boolean)
Dim oDirectory As DirectoryInfo = New DirectoryInfo(SourceDirName)
Dim oDirectory As New DirectoryInfo(SourceDirName)
If Not oDirectory.Exists Then
Throw New DirectoryNotFoundException("Source directory does not exist or could not be found: " & SourceDirName)
@@ -392,6 +399,34 @@ Public Class File
Return oIsDirectory
End Function
''' <summary>
''' Checks the size of the supplied file.
''' </summary>
''' <param name="pFilePath"></param>
''' <param name="pMaxFileSizeInMegaBytes"></param>
''' <returns></returns>
Public Function TestFileSizeIsLessThanMaxFileSize(pFilePath As String, pMaxFileSizeInMegabytes As Integer) As Boolean
Dim oFileInfo As New FileInfo(pFilePath)
_Logger.Info("Checking Filesize of {0}", oFileInfo.Name)
_Logger.Debug("Filesize threshold is {0} MB.", pMaxFileSizeInMegabytes)
If pMaxFileSizeInMegabytes <= 0 Then
_Logger.Debug("Filesize is not configured. Skipping check.")
Return True
End If
Dim oMaxSize = pMaxFileSizeInMegabytes * 1024 * 1024
If oMaxSize > 0 And oFileInfo.Length > oMaxSize Then
_Logger.Debug("Filesize is bigger than threshold.")
Return False
Else
_Logger.Debug("Filesize is smaller than threshold. All fine.")
Return True
End If
End Function
Public Function GetDateDirectory(pBaseDirectory As String, pDate As Date) As String
Dim oDateDirectory = GetDateString(pDate)
Dim oFinalDirectory As String = IO.Path.Combine(pBaseDirectory, oDateDirectory)
@@ -457,5 +492,4 @@ Public Class File
Public Function GetFilenameWithPrefix(pBaseString As String, pPrefix As String, pExtension As String)
Return $"{pPrefix}-{pBaseString}.{pExtension}"
End Function
End Class

43
Base/GraphicsEx.vb Normal file
View File

@@ -0,0 +1,43 @@
Imports System.Drawing
Public Class GraphicsEx
''' <summary>
''' Returns the brightness of a color as a number between 0 and 1
''' </summary>
''' <param name="pColor">The color to check</param>
''' <returns>Low values for dark colors, high values for bright colors.</returns>
Public Shared Function GetBrightness(pColor As Color) As Single
Return (pColor.R * 0.299F + pColor.G * 0.587F + pColor.B * 0.114F) / 256.0F
End Function
''' <summary>
''' Returns a foreground/text color of either black or white, depending on the brightness of `pOtherColor`
''' </summary>
''' <param name="pOtherColor">The Background color whose brightness is determined</param>
''' <returns>A text color which is either white or black</returns>
Public Shared Function GetContrastedColor(pOtherColor As Color) As Color
If GetBrightness(pOtherColor) < 0.55 Then
Return Color.White
Else
Return Color.Black
End If
End Function
Public Sub DrawRectangle(Bounds As Rectangle)
Dim oContext As IntPtr
oContext = NativeMethods.GetDC(IntPtr.Zero)
Try
Dim g As Graphics
g = Graphics.FromHdc(oContext)
Try
g.DrawRectangle(Pens.Red, Bounds)
Finally
g.Dispose()
End Try
Finally
NativeMethods.ReleaseDC(IntPtr.Zero, oContext)
End Try
End Sub
End Class

View File

@@ -1,15 +0,0 @@
Namespace IDB
Public Class Attributes
Public Const ATTRIBUTE_DOCTYPE = "Doctype"
Public Const ATTRIBUTE_DYNAMIC_FOLDER = "Dynamic Folder"
Public Const ATTRIBUTE_ORIGIN_FILENAME = "OriginFileName"
Public Const ATTRIBUTE_ORIGIN_CHANGED = "OriginChangedDatetime"
Public Const ATTRIBUTE_ORIGIN_CREATED = "OriginCreationDatetime"
Public Const ATTRIBUTE_DISPLAY_FILENAME = "DisplayFileName"
Public Const ATTRIBUTE_DISPLAY_FILENAME1 = "DisplayFileName1"
End Class
End Namespace

43
Base/IDB/Constants.vb Normal file
View File

@@ -0,0 +1,43 @@
Namespace IDB
Public Class Constants
Public Class FileStore
Public Const FILE_STORE_INVALID_OBEJCT_ID = 0
Public Const FILE_CHANGED_QUESTION = "QUESTION VERSION"
Public Const FILE_CHANGED_OVERWRITE = "AUTO REPLACE"
Public Const FILE_CHANGED_VERSION = "AUTO VERSION"
Public Const OBJECT_STATE_FILE_ADDED = "File added"
Public Const OBJECT_STATE_FILE_VERSIONED = "File versioned"
Public Const OBJECT_STATE_FILE_CHANGED = "File changed"
Public Const OBJECT_STATE_FILE_OPENED = "File opened"
Public Const OBJECT_STATE_FILE_DELETED = "File deleted"
Public Const OBJECT_STATE_METADATA_CHANGED = "Metadata changed"
Public Const OBJECT_STATE_ATTRIBUTEVALUE_DELETED = "Attributevalue deleted"
Public Const OBJECT_STATE_FILE_CHECKED_OUT = "File Checked Out"
Public Const OBJECT_STATE_FILE_CHECKED_IN = "File Checked In"
End Class
Public Class Database
Public Enum NamedDatabase
ECM
IDB
End Enum
End Class
Public Class Attributes
Public Const ATTRIBUTE_DOCTYPE = "Doctype"
Public Const ATTRIBUTE_DYNAMIC_FOLDER = "Dynamic Folder"
Public Const ATTRIBUTE_ORIGIN_FILENAME = "OriginFileName"
Public Const ATTRIBUTE_ORIGIN_CHANGED = "OriginChangedDatetime"
Public Const ATTRIBUTE_ORIGIN_CREATED = "OriginCreationDatetime"
Public Const ATTRIBUTE_DISPLAY_FILENAME = "DisplayFileName"
Public Const ATTRIBUTE_DISPLAY_FILENAME1 = "DisplayFileName1"
End Class
End Class
End Namespace

View File

@@ -1,11 +0,0 @@
Namespace IDB
Public Class Database
Public Enum NamedDatabase
ECM
IDB
End Enum
End Class
End Namespace

View File

@@ -1,20 +0,0 @@
Namespace IDB
Public Class FileStore
Public Const FILE_STORE_INVALID_OBEJCT_ID = 0
Public Const FILE_CHANGED_QUESTION = "QUESTION VERSION"
Public Const FILE_CHANGED_OVERWRITE = "AUTO REPLACE"
Public Const FILE_CHANGED_VERSION = "AUTO VERSION"
Public Const OBJECT_STATE_FILE_ADDED = "File added"
Public Const OBJECT_STATE_FILE_VERSIONED = "File versioned"
Public Const OBJECT_STATE_FILE_CHANGED = "File changed"
Public Const OBJECT_STATE_FILE_OPENED = "File opened"
Public Const OBJECT_STATE_FILE_DELETED = "File deleted"
Public Const OBJECT_STATE_METADATA_CHANGED = "Metadata changed"
Public Const OBJECT_STATE_ATTRIBUTEVALUE_DELETED = "Attributevalue deleted"
Public Const OBJECT_STATE_FILE_CHECKED_OUT = "File Checked Out"
Public Const OBJECT_STATE_FILE_CHECKED_IN = "File Checked In"
End Class
End Namespace

55
Base/LanguageEx.vb Normal file
View File

@@ -0,0 +1,55 @@
Imports System.Globalization
Imports System.Threading
Imports DigitalData.Modules.Logging
''' <summary>
''' Functions relating to i18n, Cultures, Translations
''' </summary>
Public Class LanguageEx
''' <summary>
''' Sets the Language of the current thread by setting CurrentCulture and CurrentUICulture
''' </summary>
''' <param name="pLogger">A Logger instance</param>
''' <param name="pUserLanguage">A language code in the form of 'de-DE'</param>
''' <param name="pUserDateFormat">A custom date pattern</param>
Public Shared Sub SetApplicationLanguage(pLogger As Logger, pUserLanguage As String, Optional pUserDateFormat As String = Nothing)
Try
pLogger.Debug("Setting application language..")
Dim Culture As New CultureInfo(pUserLanguage)
If String.IsNullOrEmpty(pUserDateFormat) = False Then
Culture.DateTimeFormat.ShortDatePattern = pUserDateFormat
End If
pLogger.Debug("Culture object for language [{0}] created", pUserLanguage)
' The following line provides localization for data formats.
Thread.CurrentThread.CurrentCulture = Culture
' The following line provides localization for the application's user interface.
Thread.CurrentThread.CurrentUICulture = Culture
' Set this culture as the default culture for all threads in this application.
' Note: The following properties are supported in the .NET Framework 4.5+
CultureInfo.DefaultThreadCurrentCulture = Culture
CultureInfo.DefaultThreadCurrentUICulture = Culture
pLogger.Debug("Application language set to [{0}]", Culture.Name)
Catch ex As Exception
pLogger.Warn("Could not set application language!")
pLogger.Error(ex)
End Try
End Sub
''' <summary>
''' Logs the culture settings of the current thread
''' </summary>
''' <param name="pLogger">A Logger instance</param>
Public Shared Sub LogApplicationLanguage(pLogger As Logger)
pLogger.Debug("=== Application Language ===")
pLogger.Debug("Thread.CurrentThread.CurrentCulture: [{0}]", Thread.CurrentThread.CurrentCulture)
pLogger.Debug("Thread.CurrentThread.CurrentUICulture: [{0}]", Thread.CurrentThread.CurrentUICulture)
pLogger.Debug("CultureInfo.DefaultThreadCurrentCulture: [{0}]", CultureInfo.DefaultThreadCurrentCulture)
pLogger.Debug("CultureInfo.DefaultThreadCurrentUICulture: [{0}]", CultureInfo.DefaultThreadCurrentUICulture)
End Sub
End Class

685
Base/MimeEx.vb Normal file
View File

@@ -0,0 +1,685 @@
Imports DigitalData.Modules.Logging
Public Class MimeEx
Inherits BaseClass
Public Sub New(pLogConfig As LogConfig)
MyBase.New(pLogConfig)
End Sub
Public Function GetMimeType(ByVal extension As String) As String
If extension Is Nothing Then
Throw New ArgumentNullException("extension")
End If
If Not extension.StartsWith(".") Then
extension = "." & extension
End If
Dim value = Nothing
If Not _mappings.Value.TryGetValue(extension, value) Then
Return "application/octet-stream"
End If
Return value
End Function
Public Function GetExtension(ByVal mimeType As String) As String
If mimeType Is Nothing Then
Throw New ArgumentNullException("mimeType")
End If
If mimeType.StartsWith(".") Then
Throw New ArgumentException("Requested mime type is not valid: " & mimeType)
End If
Dim value = Nothing
If _mappings.Value.TryGetValue(mimeType, value) Then
Return value
End If
Throw New ArgumentException("Requested mime type is not registered: " & mimeType)
End Function
Private ReadOnly _mappings As New Lazy(Of IDictionary(Of String, String))(AddressOf BuildMappings)
Private Function BuildMappings() As IDictionary(Of String, String)
Dim dictionary As New Dictionary(Of String, String)(StringComparer.InvariantCultureIgnoreCase) From {
{".323", "text/h323"},
{".3g2", "video/3gpp2"},
{".3gp", "video/3gpp"},
{".3gp2", "video/3gpp2"},
{".3gpp", "video/3gpp"},
{".7z", "application/x-7z-compressed"},
{".aa", "audio/audible"},
{".AAC", "audio/aac"},
{".aaf", "application/octet-stream"},
{".aax", "audio/vnd.audible.aax"},
{".ac3", "audio/ac3"},
{".aca", "application/octet-stream"},
{".accda", "application/msaccess.addin"},
{".accdb", "application/msaccess"},
{".accdc", "application/msaccess.cab"},
{".accde", "application/msaccess"},
{".accdr", "application/msaccess.runtime"},
{".accdt", "application/msaccess"},
{".accdw", "application/msaccess.webapplication"},
{".accft", "application/msaccess.ftemplate"},
{".acx", "application/internet-property-stream"},
{".AddIn", "text/xml"},
{".ade", "application/msaccess"},
{".adobebridge", "application/x-bridge-url"},
{".adp", "application/msaccess"},
{".ADT", "audio/vnd.dlna.adts"},
{".ADTS", "audio/aac"},
{".afm", "application/octet-stream"},
{".ai", "application/postscript"},
{".aif", "audio/x-aiff"},
{".aifc", "audio/aiff"},
{".aiff", "audio/aiff"},
{".air", "application/vnd.adobe.air-application-installer-package+zip"},
{".amc", "application/x-mpeg"},
{".application", "application/x-ms-application"},
{".art", "image/x-jg"},
{".asa", "application/xml"},
{".asax", "application/xml"},
{".ascx", "application/xml"},
{".asd", "application/octet-stream"},
{".asf", "video/x-ms-asf"},
{".ashx", "application/xml"},
{".asi", "application/octet-stream"},
{".asm", "text/plain"},
{".asmx", "application/xml"},
{".aspx", "application/xml"},
{".asr", "video/x-ms-asf"},
{".asx", "video/x-ms-asf"},
{".atom", "application/atom+xml"},
{".au", "audio/basic"},
{".avi", "video/x-msvideo"},
{".axs", "application/olescript"},
{".bas", "text/plain"},
{".bcpio", "application/x-bcpio"},
{".bin", "application/octet-stream"},
{".bmp", "image/bmp"},
{".c", "text/plain"},
{".cab", "application/octet-stream"},
{".caf", "audio/x-caf"},
{".calx", "application/vnd.ms-office.calx"},
{".cat", "application/vnd.ms-pki.seccat"},
{".cc", "text/plain"},
{".cd", "text/plain"},
{".cdda", "audio/aiff"},
{".cdf", "application/x-cdf"},
{".cer", "application/x-x509-ca-cert"},
{".chm", "application/octet-stream"},
{".class", "application/x-java-applet"},
{".clp", "application/x-msclip"},
{".cmx", "image/x-cmx"},
{".cnf", "text/plain"},
{".cod", "image/cis-cod"},
{".config", "application/xml"},
{".contact", "text/x-ms-contact"},
{".coverage", "application/xml"},
{".cpio", "application/x-cpio"},
{".cpp", "text/plain"},
{".crd", "application/x-mscardfile"},
{".crl", "application/pkix-crl"},
{".crt", "application/x-x509-ca-cert"},
{".cs", "text/plain"},
{".csdproj", "text/plain"},
{".csh", "application/x-csh"},
{".csproj", "text/plain"},
{".css", "text/css"},
{".csv", "text/csv"},
{".cur", "application/octet-stream"},
{".cxx", "text/plain"},
{".dat", "application/octet-stream"},
{".datasource", "application/xml"},
{".dbproj", "text/plain"},
{".dcr", "application/x-director"},
{".def", "text/plain"},
{".deploy", "application/octet-stream"},
{".der", "application/x-x509-ca-cert"},
{".dgml", "application/xml"},
{".dib", "image/bmp"},
{".dif", "video/x-dv"},
{".dir", "application/x-director"},
{".disco", "text/xml"},
{".divx", "video/divx"},
{".dll", "application/x-msdownload"},
{".dll.config", "text/xml"},
{".dlm", "text/dlm"},
{".doc", "application/msword"},
{".docm", "application/vnd.ms-word.document.macroEnabled.12"},
{".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
{".dot", "application/msword"},
{".dotm", "application/vnd.ms-word.template.macroEnabled.12"},
{".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"},
{".dsp", "application/octet-stream"},
{".dsw", "text/plain"},
{".dtd", "text/xml"},
{".dtsConfig", "text/xml"},
{".dv", "video/x-dv"},
{".dvi", "application/x-dvi"},
{".dwf", "drawing/x-dwf"},
{".dwp", "application/octet-stream"},
{".dxr", "application/x-director"},
{".eml", "message/rfc822"},
{".emz", "application/octet-stream"},
{".eot", "application/octet-stream"},
{".eps", "application/postscript"},
{".etl", "application/etl"},
{".etx", "text/x-setext"},
{".evy", "application/envoy"},
{".exe", "application/octet-stream"},
{".exe.config", "text/xml"},
{".fdf", "application/vnd.fdf"},
{".fif", "application/fractals"},
{".filters", "application/xml"},
{".fla", "application/octet-stream"},
{".flr", "x-world/x-vrml"},
{".flv", "video/x-flv"},
{".fsscript", "application/fsharp-script"},
{".fsx", "application/fsharp-script"},
{".generictest", "application/xml"},
{".gif", "image/gif"},
{".group", "text/x-ms-group"},
{".gsm", "audio/x-gsm"},
{".gtar", "application/x-gtar"},
{".gz", "application/x-gzip"},
{".h", "text/plain"},
{".hdf", "application/x-hdf"},
{".hdml", "text/x-hdml"},
{".hhc", "application/x-oleobject"},
{".hhk", "application/octet-stream"},
{".hhp", "application/octet-stream"},
{".hlp", "application/winhlp"},
{".hpp", "text/plain"},
{".hqx", "application/mac-binhex40"},
{".hta", "application/hta"},
{".htc", "text/x-component"},
{".htm", "text/html"},
{".html", "text/html"},
{".htt", "text/webviewhtml"},
{".hxa", "application/xml"},
{".hxc", "application/xml"},
{".hxd", "application/octet-stream"},
{".hxe", "application/xml"},
{".hxf", "application/xml"},
{".hxh", "application/octet-stream"},
{".hxi", "application/octet-stream"},
{".hxk", "application/xml"},
{".hxq", "application/octet-stream"},
{".hxr", "application/octet-stream"},
{".hxs", "application/octet-stream"},
{".hxt", "text/html"},
{".hxv", "application/xml"},
{".hxw", "application/octet-stream"},
{".hxx", "text/plain"},
{".i", "text/plain"},
{".ico", "image/x-icon"},
{".ics", "application/octet-stream"},
{".idl", "text/plain"},
{".ief", "image/ief"},
{".iii", "application/x-iphone"},
{".inc", "text/plain"},
{".inf", "application/octet-stream"},
{".inl", "text/plain"},
{".ins", "application/x-internet-signup"},
{".ipa", "application/x-itunes-ipa"},
{".ipg", "application/x-itunes-ipg"},
{".ipproj", "text/plain"},
{".ipsw", "application/x-itunes-ipsw"},
{".iqy", "text/x-ms-iqy"},
{".isp", "application/x-internet-signup"},
{".ite", "application/x-itunes-ite"},
{".itlp", "application/x-itunes-itlp"},
{".itms", "application/x-itunes-itms"},
{".itpc", "application/x-itunes-itpc"},
{".IVF", "video/x-ivf"},
{".jar", "application/java-archive"},
{".java", "application/octet-stream"},
{".jck", "application/liquidmotion"},
{".jcz", "application/liquidmotion"},
{".jfif", "image/pjpeg"},
{".jnlp", "application/x-java-jnlp-file"},
{".jpb", "application/octet-stream"},
{".jpe", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".js", "application/x-javascript"},
{".json", "application/json"},
{".jsx", "text/jscript"},
{".jsxbin", "text/plain"},
{".latex", "application/x-latex"},
{".library-ms", "application/windows-library+xml"},
{".lit", "application/x-ms-reader"},
{".loadtest", "application/xml"},
{".lpk", "application/octet-stream"},
{".lsf", "video/x-la-asf"},
{".lst", "text/plain"},
{".lsx", "video/x-la-asf"},
{".lzh", "application/octet-stream"},
{".m13", "application/x-msmediaview"},
{".m14", "application/x-msmediaview"},
{".m1v", "video/mpeg"},
{".m2t", "video/vnd.dlna.mpeg-tts"},
{".m2ts", "video/vnd.dlna.mpeg-tts"},
{".m2v", "video/mpeg"},
{".m3u", "audio/x-mpegurl"},
{".m3u8", "audio/x-mpegurl"},
{".m4a", "audio/m4a"},
{".m4b", "audio/m4b"},
{".m4p", "audio/m4p"},
{".m4r", "audio/x-m4r"},
{".m4v", "video/x-m4v"},
{".mac", "image/x-macpaint"},
{".mak", "text/plain"},
{".man", "application/x-troff-man"},
{".manifest", "application/x-ms-manifest"},
{".map", "text/plain"},
{".master", "application/xml"},
{".mda", "application/msaccess"},
{".mdb", "application/x-msaccess"},
{".mde", "application/msaccess"},
{".mdp", "application/octet-stream"},
{".me", "application/x-troff-me"},
{".mfp", "application/x-shockwave-flash"},
{".mht", "message/rfc822"},
{".mhtml", "message/rfc822"},
{".mid", "audio/mid"},
{".midi", "audio/mid"},
{".mix", "application/octet-stream"},
{".mk", "text/plain"},
{".mmf", "application/x-smaf"},
{".mno", "text/xml"},
{".mny", "application/x-msmoney"},
{".mod", "video/mpeg"},
{".mov", "video/quicktime"},
{".movie", "video/x-sgi-movie"},
{".mp2", "video/mpeg"},
{".mp2v", "video/mpeg"},
{".mp3", "audio/mpeg"},
{".mp4", "video/mp4"},
{".mp4v", "video/mp4"},
{".mpa", "video/mpeg"},
{".mpe", "video/mpeg"},
{".mpeg", "video/mpeg"},
{".mpf", "application/vnd.ms-mediapackage"},
{".mpg", "video/mpeg"},
{".mpp", "application/vnd.ms-project"},
{".mpv2", "video/mpeg"},
{".mqv", "video/quicktime"},
{".ms", "application/x-troff-ms"},
{".msg", "application/vnd.ms-outlook"},
{".msi", "application/octet-stream"},
{".mso", "application/octet-stream"},
{".mts", "video/vnd.dlna.mpeg-tts"},
{".mtx", "application/xml"},
{".mvb", "application/x-msmediaview"},
{".mvc", "application/x-miva-compiled"},
{".mxp", "application/x-mmxp"},
{".nc", "application/x-netcdf"},
{".nsc", "video/x-ms-asf"},
{".nws", "message/rfc822"},
{".ocx", "application/octet-stream"},
{".oda", "application/oda"},
{".odb", "application/vnd.oasis.opendocument.database"},
{".odc", "application/vnd.oasis.opendocument.chart"},
{".odf", "application/vnd.oasis.opendocument.formula"},
{".odg", "application/vnd.oasis.opendocument.graphics"},
{".odh", "text/plain"},
{".odi", "application/vnd.oasis.opendocument.image"},
{".odl", "text/plain"},
{".odm", "application/vnd.oasis.opendocument.text-master"},
{".odp", "application/vnd.oasis.opendocument.presentation"},
{".ods", "application/vnd.oasis.opendocument.spreadsheet"},
{".odt", "application/vnd.oasis.opendocument.text"},
{".ogv", "video/ogg"},
{".one", "application/onenote"},
{".onea", "application/onenote"},
{".onepkg", "application/onenote"},
{".onetmp", "application/onenote"},
{".onetoc", "application/onenote"},
{".onetoc2", "application/onenote"},
{".orderedtest", "application/xml"},
{".osdx", "application/opensearchdescription+xml"},
{".otg", "application/vnd.oasis.opendocument.graphics-template"},
{".oth", "application/vnd.oasis.opendocument.text-web"},
{".otp", "application/vnd.oasis.opendocument.presentation-template"},
{".ots", "application/vnd.oasis.opendocument.spreadsheet-template"},
{".ott", "application/vnd.oasis.opendocument.text-template"},
{".oxt", "application/vnd.openofficeorg.extension"},
{".p10", "application/pkcs10"},
{".p12", "application/x-pkcs12"},
{".p7b", "application/x-pkcs7-certificates"},
{".p7c", "application/pkcs7-mime"},
{".p7m", "application/pkcs7-mime"},
{".p7r", "application/x-pkcs7-certreqresp"},
{".p7s", "application/pkcs7-signature"},
{".pbm", "image/x-portable-bitmap"},
{".pcast", "application/x-podcast"},
{".pct", "image/pict"},
{".pcx", "application/octet-stream"},
{".pcz", "application/octet-stream"},
{".pdf", "application/pdf"},
{".pfb", "application/octet-stream"},
{".pfm", "application/octet-stream"},
{".pfx", "application/x-pkcs12"},
{".pgm", "image/x-portable-graymap"},
{".pic", "image/pict"},
{".pict", "image/pict"},
{".pkgdef", "text/plain"},
{".pkgundef", "text/plain"},
{".pko", "application/vnd.ms-pki.pko"},
{".pls", "audio/scpls"},
{".pma", "application/x-perfmon"},
{".pmc", "application/x-perfmon"},
{".pml", "application/x-perfmon"},
{".pmr", "application/x-perfmon"},
{".pmw", "application/x-perfmon"},
{".png", "image/png"},
{".pnm", "image/x-portable-anymap"},
{".pnt", "image/x-macpaint"},
{".pntg", "image/x-macpaint"},
{".pnz", "image/png"},
{".pot", "application/vnd.ms-powerpoint"},
{".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"},
{".potx", "application/vnd.openxmlformats-officedocument.presentationml.template"},
{".ppa", "application/vnd.ms-powerpoint"},
{".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"},
{".ppm", "image/x-portable-pixmap"},
{".pps", "application/vnd.ms-powerpoint"},
{".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"},
{".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"},
{".ppt", "application/vnd.ms-powerpoint"},
{".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"},
{".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
{".prf", "application/pics-rules"},
{".prm", "application/octet-stream"},
{".prx", "application/octet-stream"},
{".ps", "application/postscript"},
{".psc1", "application/PowerShell"},
{".psd", "application/octet-stream"},
{".psess", "application/xml"},
{".psm", "application/octet-stream"},
{".psp", "application/octet-stream"},
{".pub", "application/x-mspublisher"},
{".pwz", "application/vnd.ms-powerpoint"},
{".qht", "text/x-html-insertion"},
{".qhtm", "text/x-html-insertion"},
{".qt", "video/quicktime"},
{".qti", "image/x-quicktime"},
{".qtif", "image/x-quicktime"},
{".qtl", "application/x-quicktimeplayer"},
{".qxd", "application/octet-stream"},
{".ra", "audio/x-pn-realaudio"},
{".ram", "audio/x-pn-realaudio"},
{".rar", "application/octet-stream"},
{".ras", "image/x-cmu-raster"},
{".rat", "application/rat-file"},
{".rc", "text/plain"},
{".rc2", "text/plain"},
{".rct", "text/plain"},
{".rdlc", "application/xml"},
{".resx", "application/xml"},
{".rf", "image/vnd.rn-realflash"},
{".rgb", "image/x-rgb"},
{".rgs", "text/plain"},
{".rm", "application/vnd.rn-realmedia"},
{".rmi", "audio/mid"},
{".rmp", "application/vnd.rn-rn_music_package"},
{".roff", "application/x-troff"},
{".rpm", "audio/x-pn-realaudio-plugin"},
{".rqy", "text/x-ms-rqy"},
{".rtf", "application/rtf"},
{".rtx", "text/richtext"},
{".ruleset", "application/xml"},
{".s", "text/plain"},
{".safariextz", "application/x-safari-safariextz"},
{".scd", "application/x-msschedule"},
{".sct", "text/scriptlet"},
{".sd2", "audio/x-sd2"},
{".sdp", "application/sdp"},
{".sea", "application/octet-stream"},
{".searchConnector-ms", "application/windows-search-connector+xml"},
{".setpay", "application/set-payment-initiation"},
{".setreg", "application/set-registration-initiation"},
{".settings", "application/xml"},
{".sgimb", "application/x-sgimb"},
{".sgml", "text/sgml"},
{".sh", "application/x-sh"},
{".shar", "application/x-shar"},
{".shtml", "text/html"},
{".sit", "application/x-stuffit"},
{".sitemap", "application/xml"},
{".skin", "application/xml"},
{".sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12"},
{".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"},
{".slk", "application/vnd.ms-excel"},
{".sln", "text/plain"},
{".slupkg-ms", "application/x-ms-license"},
{".smd", "audio/x-smd"},
{".smi", "application/octet-stream"},
{".smx", "audio/x-smd"},
{".smz", "audio/x-smd"},
{".snd", "audio/basic"},
{".snippet", "application/xml"},
{".snp", "application/octet-stream"},
{".sol", "text/plain"},
{".sor", "text/plain"},
{".spc", "application/x-pkcs7-certificates"},
{".spl", "application/futuresplash"},
{".src", "application/x-wais-source"},
{".srf", "text/plain"},
{".SSISDeploymentManifest", "text/xml"},
{".ssm", "application/streamingmedia"},
{".sst", "application/vnd.ms-pki.certstore"},
{".stl", "application/vnd.ms-pki.stl"},
{".sv4cpio", "application/x-sv4cpio"},
{".sv4crc", "application/x-sv4crc"},
{".svc", "application/xml"},
{".svg", "image/svg+xml"},
{".swf", "application/x-shockwave-flash"},
{".t", "application/x-troff"},
{".tar", "application/x-tar"},
{".tcl", "application/x-tcl"},
{".testrunconfig", "application/xml"},
{".testsettings", "application/xml"},
{".tex", "application/x-tex"},
{".texi", "application/x-texinfo"},
{".texinfo", "application/x-texinfo"},
{".tgz", "application/x-compressed"},
{".thmx", "application/vnd.ms-officetheme"},
{".thn", "application/octet-stream"},
{".tif", "image/tiff"},
{".tiff", "image/tiff"},
{".tlh", "text/plain"},
{".tli", "text/plain"},
{".toc", "application/octet-stream"},
{".tr", "application/x-troff"},
{".trm", "application/x-msterminal"},
{".trx", "application/xml"},
{".ts", "video/vnd.dlna.mpeg-tts"},
{".tsv", "text/tab-separated-values"},
{".ttf", "application/octet-stream"},
{".tts", "video/vnd.dlna.mpeg-tts"},
{".txt", "text/plain"},
{".u32", "application/octet-stream"},
{".uls", "text/iuls"},
{".user", "text/plain"},
{".ustar", "application/x-ustar"},
{".vb", "text/plain"},
{".vbdproj", "text/plain"},
{".vbk", "video/mpeg"},
{".vbproj", "text/plain"},
{".vbs", "text/vbscript"},
{".vcf", "text/x-vcard"},
{".vcproj", "application/xml"},
{".vcs", "text/plain"},
{".vcxproj", "application/xml"},
{".vddproj", "text/plain"},
{".vdp", "text/plain"},
{".vdproj", "text/plain"},
{".vdx", "application/vnd.ms-visio.viewer"},
{".vml", "text/xml"},
{".vscontent", "application/xml"},
{".vsct", "text/xml"},
{".vsd", "application/vnd.visio"},
{".vsi", "application/ms-vsi"},
{".vsix", "application/vsix"},
{".vsixlangpack", "text/xml"},
{".vsixmanifest", "text/xml"},
{".vsmdi", "application/xml"},
{".vspscc", "text/plain"},
{".vss", "application/vnd.visio"},
{".vsscc", "text/plain"},
{".vssettings", "text/xml"},
{".vssscc", "text/plain"},
{".vst", "application/vnd.visio"},
{".vstemplate", "text/xml"},
{".vsto", "application/x-ms-vsto"},
{".vsw", "application/vnd.visio"},
{".vsx", "application/vnd.visio"},
{".vtx", "application/vnd.visio"},
{".wav", "audio/wav"},
{".wave", "audio/wav"},
{".wax", "audio/x-ms-wax"},
{".wbk", "application/msword"},
{".wbmp", "image/vnd.wap.wbmp"},
{".wcm", "application/vnd.ms-works"},
{".wdb", "application/vnd.ms-works"},
{".wdp", "image/vnd.ms-photo"},
{".webarchive", "application/x-safari-webarchive"},
{".webm", "video/webm"},
{".webp", "image/webp"},
{".webtest", "application/xml"},
{".wiq", "application/xml"},
{".wiz", "application/msword"},
{".wks", "application/vnd.ms-works"},
{".WLMP", "application/wlmoviemaker"},
{".wlpginstall", "application/x-wlpg-detect"},
{".wlpginstall3", "application/x-wlpg3-detect"},
{".wm", "video/x-ms-wm"},
{".wma", "audio/x-ms-wma"},
{".wmd", "application/x-ms-wmd"},
{".wmf", "application/x-msmetafile"},
{".wml", "text/vnd.wap.wml"},
{".wmlc", "application/vnd.wap.wmlc"},
{".wmls", "text/vnd.wap.wmlscript"},
{".wmlsc", "application/vnd.wap.wmlscriptc"},
{".wmp", "video/x-ms-wmp"},
{".wmv", "video/x-ms-wmv"},
{".wmx", "video/x-ms-wmx"},
{".wmz", "application/x-ms-wmz"},
{".wpl", "application/vnd.ms-wpl"},
{".wps", "application/vnd.ms-works"},
{".wri", "application/x-mswrite"},
{".wrl", "x-world/x-vrml"},
{".wrz", "x-world/x-vrml"},
{".wsc", "text/scriptlet"},
{".wsdl", "text/xml"},
{".wvx", "video/x-ms-wvx"},
{".x", "application/directx"},
{".xaf", "x-world/x-vrml"},
{".xaml", "application/xaml+xml"},
{".xap", "application/x-silverlight-app"},
{".xbap", "application/x-ms-xbap"},
{".xbm", "image/x-xbitmap"},
{".xdr", "text/plain"},
{".xht", "application/xhtml+xml"},
{".xhtml", "application/xhtml+xml"},
{".xla", "application/vnd.ms-excel"},
{".xlam", "application/vnd.ms-excel.addin.macroEnabled.12"},
{".xlc", "application/vnd.ms-excel"},
{".xld", "application/vnd.ms-excel"},
{".xlk", "application/vnd.ms-excel"},
{".xll", "application/vnd.ms-excel"},
{".xlm", "application/vnd.ms-excel"},
{".xls", "application/vnd.ms-excel"},
{".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"},
{".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"},
{".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{".xlt", "application/vnd.ms-excel"},
{".xltm", "application/vnd.ms-excel.template.macroEnabled.12"},
{".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"},
{".xlw", "application/vnd.ms-excel"},
{".xml", "text/xml"},
{".xmta", "application/xml"},
{".xof", "x-world/x-vrml"},
{".XOML", "text/plain"},
{".xpm", "image/x-xpixmap"},
{".xps", "application/vnd.ms-xpsdocument"},
{".xrm-ms", "text/xml"},
{".xsc", "application/xml"},
{".xsd", "text/xml"},
{".xsf", "text/xml"},
{".xsl", "text/xml"},
{".xslt", "text/xml"},
{".xsn", "application/octet-stream"},
{".xss", "application/xml"},
{".xtp", "application/octet-stream"},
{".xwd", "image/x-xwindowdump"},
{".z", "application/x-compress"},
{".zip", "application/x-zip-compressed"},
{"application/fsharp-script", ".fsx"},
{"application/msaccess", ".adp"},
{"application/msword", ".doc"},
{"application/octet-stream", ".bin"},
{"application/onenote", ".one"},
{"application/postscript", ".eps"},
{"application/vnd.ms-excel", ".xls"},
{"application/vnd.ms-powerpoint", ".ppt"},
{"application/vnd.ms-works", ".wks"},
{"application/vnd.visio", ".vsd"},
{"application/x-director", ".dir"},
{"application/x-shockwave-flash", ".swf"},
{"application/x-x509-ca-cert", ".cer"},
{"application/xhtml+xml", ".xhtml"},
{"application/xml", ".xml"},
{"audio/aac", ".AAC"},
{"audio/aiff", ".aiff"},
{"audio/basic", ".snd"},
{"audio/mid", ".midi"},
{"audio/wav", ".wav"},
{"audio/x-mpegurl", ".m3u"},
{"audio/x-pn-realaudio", ".ra"},
{"audio/x-smd", ".smd"},
{"image/bmp", ".bmp"},
{"image/jpeg", ".jpg"},
{"image/pict", ".pic"},
{"image/png", ".png"},
{"image/tiff", ".tiff"},
{"image/x-macpaint", ".mac"},
{"image/x-quicktime", ".qti"},
{"message/rfc822", ".eml"},
{"text/html", ".html"},
{"text/plain", ".txt"},
{"text/scriptlet", ".wsc"},
{"text/xml", ".xml"},
{"video/3gpp", ".3gp"},
{"video/3gpp2", ".3gp2"},
{"video/mp4", ".mp4"},
{"video/mpeg", ".mpg"},
{"video/quicktime", ".mov"},
{"video/vnd.dlna.mpeg-tts", ".m2t"},
{"video/x-dv", ".dv"},
{"video/x-la-asf", ".lsf"},
{"video/x-ms-asf", ".asf"},
{"x-world/x-vrml", ".xof"}
}
Dim dictionary2 As Dictionary(Of String, String) = dictionary
Dim list As List(Of KeyValuePair(Of String, String)) = dictionary2.ToList()
For Each item As KeyValuePair(Of String, String) In list
If Not dictionary2.ContainsKey(item.Value) Then
dictionary2.Add(item.Value, item.Key)
End If
Next
Return dictionary2
End Function
End Class

150
Base/ModuleExtensions.vb Normal file
View File

@@ -0,0 +1,150 @@
Imports System.Runtime.CompilerServices
Imports System.Web
Public Module ModuleExtensions
Const UnixEraStartTicks As Long = 621355968000000000
' ======================================================
' === DATETIME
' ======================================================
<Extension()>
Public Function GetUnixTimestamp(pDate As Date) As Long
Dim UnixEraTicks = pDate.Ticks - UnixEraStartTicks
Return UnixEraTicks \ 10000
End Function
<Extension()>
Public Function DateFromUnix(pTimestamp As Long) As Date
Return New Date(UnixEraStartTicks + pTimestamp * 10000)
End Function
' ======================================================
' === LIST
' ======================================================
<Extension()>
Public Function JoinToString(pList As IEnumerable(Of String), pSeparator As Char)
Return String.Join(pSeparator, pList)
End Function
' ======================================================
' === STRING
' ======================================================
''' <summary>
''' Truncates a string to the specified length if it exceeds that length.
''' </summary>
''' <param name="pString">The string</param>
''' <param name="pLength">The maximum string length</param>
''' <returns>The truncated string</returns>
<Extension()>
Public Function Truncate(pString As String, pLength As Integer) As String
If String.IsNullOrEmpty(pString) Then Return pString
Return pString.Substring(0, Math.Min(pLength, pString.Length))
End Function
''' <summary>
''' Replaces single quotes in text for SQL Commands.
''' </summary>
''' <param name="pString">The string</param>
''' <returns>The escaped string.</returns>
<Extension()>
Public Function EscapeForSQL(pString As String) As String
Return ObjectEx.NotNull(pString, String.Empty).Replace("'", "''")
End Function
''' <summary>
''' Converts a string to boolean. Accepts true and 1 as truthy values
''' </summary>
''' <param name="pString">The input string</param>
''' <returns>True if input is true or 1, otherwise false.</returns>
<Extension()>
Public Function ToBoolean(pString As String) As Boolean
If String.IsNullOrEmpty(pString) Then Return False
Return (pString.Trim().ToLower() = "true") OrElse (pString.Trim() = "1")
End Function
' ======================================================
' === DICTIONARY
' ======================================================
<Extension()>
Public Function ToURLQueryString(pDictionary As IDictionary(Of String, String)) As String
Dim oQueryString = HttpUtility.ParseQueryString(String.Empty)
For Each oItem As KeyValuePair(Of String, String) In pDictionary
oQueryString.Add(oItem.Key, oItem.Value)
Next
Return oQueryString.ToString()
End Function
' ======================================================
' === DATATABLE
' ======================================================
<Extension()>
Public Function ItemEx(Of T)(pRow As DataRow, pFieldName As String, Optional pDefaultValue As T = Nothing) As T
Try
If TableContainsColumn(pRow.Table, pFieldName) = False Then Return pDefaultValue
Return ObjectEx.NotNull(pRow.Item(pFieldName), pDefaultValue)
Catch ex As Exception
Return Nothing
End Try
End Function
<Extension()>
Public Function ItemEx(Of T)(pRow As DataRow, pFieldIndex As Integer, Optional pDefaultValue As T = Nothing) As T
Try
If TableContainsColumn(pRow.Table, pFieldIndex) = False Then Return pDefaultValue
Return ObjectEx.NotNull(pRow.Item(pFieldIndex), pDefaultValue)
Catch ex As Exception
Return Nothing
End Try
End Function
<Extension()>
Public Function FieldOrDefault(Of T)(pRow As DataRow, pFieldName As String, Optional pDefaultValue As T = Nothing) As T
Return ItemEx(pRow, pFieldName, pDefaultValue)
End Function
<Extension()>
Public Function FieldOrDefault(Of T)(pRow As DataRow, pFieldIndex As Integer, Optional pDefaultValue As T = Nothing) As T
Return ItemEx(pRow, pFieldIndex, pDefaultValue)
End Function
<Extension()>
Public Function First(pTable As DataTable) As DataRow
Try
If pTable Is Nothing OrElse pTable.Rows.Count = 0 Then
Return Nothing
End If
Return pTable.Rows.Item(0)
Catch ex As Exception
Return Nothing
End Try
End Function
Private Function TableContainsColumn(pTable As DataTable, pColumnName As String) As Boolean
Try
If pTable Is Nothing Then Return False
If String.IsNullOrEmpty(pColumnName) Then Return False
Return pTable.Columns.Contains(pColumnName)
Catch ex As Exception
Return False
End Try
End Function
Private Function TableContainsColumn(pTable As DataTable, pColumnIndex As Integer) As Boolean
Try
If pTable Is Nothing Then Return False
If String.IsNullOrEmpty(pColumnIndex) Then Return False
Return pTable.Columns.Count > pColumnIndex
Catch ex As Exception
Return False
End Try
End Function
End Module

View File

@@ -12,8 +12,8 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("Base")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("")>
<Assembly: AssemblyCopyright("Copyright © 2023")>
<Assembly: AssemblyTrademark("1.3.6.0")>
<Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' indem Sie "*" wie unten gezeigt eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.0.0.1")>
<Assembly: AssemblyFileVersion("1.0.0.1")>
<Assembly: AssemblyVersion("1.3.6.0")>
<Assembly: AssemblyFileVersion("1.3.6.0")>

View File

@@ -22,7 +22,7 @@ Namespace My.Resources
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _

View File

@@ -15,7 +15,7 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase

237
Base/NativeMethods.vb Normal file
View File

@@ -0,0 +1,237 @@
Imports System.Runtime.InteropServices
Imports System.Text
Imports DigitalData.Modules.Base.ScreenEx
Public Class NativeMethods
Public Declare Function GetWindowTextLength Lib "user32.dll" Alias "GetWindowTextLengthA" (ByVal hwnd As Int32) As Integer
Public Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal WinTitle As String, ByVal MaxLength As Integer) As Integer
<DllImport("Shell32", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Shared Function ShellExecuteEx(ByRef lpExecInfo As ShellExecuteInfo) As Boolean
End Function
<DllImport("user32", EntryPoint:="SetClipboardViewer")>
Public Shared Function SetClipboardViewer(ByVal hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function ReleaseDC(ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As IntPtr
End Function
<DllImport("User32.dll")>
Public Shared Function ReleaseCapture() As Boolean
End Function
<DllImport("user32.dll")>
Public Shared Function GetWindowRect(ByVal hWnd As HandleRef, ByRef lpRect As RectangleAPI) As Boolean
End Function
<DllImport("user32.dll")>
Public Shared Function AttachThreadInput(ByVal idAttach As IntPtr, ByVal idAttachTo As IntPtr, fAttach As Boolean) As Boolean
End Function
<DllImport("user32.dll")>
Public Shared Function GetFocus() As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function WindowFromPoint(ByVal p As PointAPI) As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function GetForegroundWindow() As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessID As Integer) As Integer
End Function
<DllImport("user32.dll")>
Public Shared Function GetClassName(ByVal hwnd As Integer, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer) As Integer
End Function
<DllImport("kernel32.dll")>
Public Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, ByVal bInheritHandle As Boolean, ByVal dwProcessId As UInteger) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function VirtualAllocEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As UIntPtr, ByVal flAllocationType As UInteger, ByVal flProtect As PageProtection) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)>
Public Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out> ByRef lpdwProcessId As UInteger) As UInteger
End Function
<DllImport("kernel32.dll")>
Public Shared Function VirtualFreeEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As UIntPtr, ByVal dwFreeType As UInteger) As Boolean
End Function
<DllImport("kernel32.dll")>
Public Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll")>
Public Shared Function MapViewOfFile(ByVal hFileMappingObject As IntPtr, ByVal dwDesiredAccess As UInteger, ByVal dwFileOffsetHigh As UInteger, ByVal dwFileOffsetLow As UInteger, ByVal dwNumberOfBytesToMap As UIntPtr) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function UnmapViewOfFile(ByVal lpBaseAddress As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)>
Public Shared Function CreateFileMapping(ByVal hFile As IntPtr, ByVal lpFileMappingAttributes As IntPtr, ByVal flProtect As PageProtection, ByVal dwMaximumSizeHigh As Integer, ByVal dwMaximumSizeLow As Integer, ByVal lpName As String) As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Shared Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr,
<Out> ByVal lpBuffer As Byte(), ByVal nSize As UIntPtr, ByVal lpNumberOfBytesRead As IntPtr) As Boolean
End Function
<DllImport("Kernel32.dll", EntryPoint:="RtlMoveMemory", SetLastError:=False)>
Public Shared Sub MoveMemoryFromByte(ByVal dest As IntPtr, ByRef src As Byte, ByVal size As Integer)
End Sub
<DllImport("Kernel32.dll", EntryPoint:="RtlMoveMemory", SetLastError:=False)>
Public Shared Sub MoveMemoryToByte(ByRef dest As Byte, ByVal src As IntPtr, ByVal size As Integer)
End Sub
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Public Shared Function RegisterWindowMessage(ByVal lpString As String) As Integer
End Function
<DllImport("user32.dll", ExactSpelling:=True, SetLastError:=True)>
Public Shared Function GetCursorPos(ByRef lpPoint As PointAPI) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("User32.dll", SetLastError:=True)>
Friend Shared Function MonitorFromWindow(ByVal hwnd As IntPtr,
ByVal dwFlags As Integer) As IntPtr
End Function
<DllImport("Shcore.dll", SetLastError:=True)>
Friend Shared Function GetDpiForMonitor(ByVal hmonitor As IntPtr,
ByVal dpiType As Monitor_DPI_Type,
ByRef dpiX As UInteger,
ByRef dpiY As UInteger) As Integer
End Function
<DllImport("gdi32.dll")>
Friend Shared Function GetDeviceCaps(ByVal hdc As IntPtr, ByVal nIndex As Integer) As Integer
End Function
Public Declare Function RegisterHotKey Lib "user32" (
ByVal Hwnd As IntPtr,
ByVal ID As Integer,
ByVal Modifiers As Integer,
ByVal Key As Integer
) As Integer
Public Declare Function UnregisterHotKey Lib "user32" (
ByVal Hwnd As IntPtr,
ByVal ID As Integer
) As Integer
Public Declare Auto Function GetWindowText Lib "user32" (
ByVal hWnd As IntPtr,
ByVal lpString As StringBuilder,
ByVal cch As Integer
) As Integer
Public Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal IDString As String) As Short
Public Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal Atom As Short) As Short
Public Const STANDARD_RIGHTS_REQUIRED As Integer = &HF0000
Public Const SECTION_QUERY As Short = &H1
Public Const SECTION_MAP_WRITE As Short = &H2
Public Const SECTION_MAP_READ As Short = &H4
Public Const SECTION_MAP_EXECUTE As Short = &H8
Public Const SECTION_EXTEND_SIZE As Short = &H10
Public Const SECTION_ALL_ACCESS As Integer = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE
Public Const FILE_MAP_ALL_ACCESS As Integer = SECTION_ALL_ACCESS
Public Const PROCESS_VM_OPERATION As Short = &H8
Public Const PROCESS_VM_READ As Short = &H10
Public Const PROCESS_VM_WRITE As Short = &H20
Public Const PROCESS_ALL_ACCESS As Long = &H1F0FFF
Public Const MEM_COMMIT As Short = &H1000
Public Const MEM_RESERVE As Short = &H2000
Public Const MEM_DECOMMIT As Short = &H4000
Public Const MEM_RELEASE As Integer = &H8000
Public Const MEM_FREE As Integer = &H10000
Public Const MEM_PRIVATE As Integer = &H20000
Public Const MEM_MAPPED As Integer = &H40000
Public Const MEM_TOP_DOWN As Integer = &H100000
Public Const INVALID_HANDLE_VALUE As Integer = -1
Public Const SW_SHOW As Short = 5
Public Const SEE_MASK_INVOKEIDLIST = &HC
Public Const SEE_MASK_NOCLOSEPROCESS = &H40
Public Const SEE_MASK_FLAG_NO_UI = &H400
Public Const ULW_COLORKEY As Integer = &H1
Public Const ULW_ALPHA As Integer = &H2
Public Const ULW_OPAQUE As Integer = &H4
Public Const AC_SRC_OVER As Byte = &H0
Public Const AC_SRC_ALPHA As Byte = &H1
Public Const HTCAPTION As Integer = &H2
Public Const WM_NCLBUTTONDOWN As Integer = &HA1
Public Const WM_HOTKEY As Integer = &H312
Public Const WM_DRAWCLIPBOARD As Integer = &H308
Public Enum PageProtection As UInteger
NoAccess = &H1
[Readonly] = &H2
ReadWrite = &H4
WriteCopy = &H8
Execute = &H10
ExecuteRead = &H20
ExecuteReadWrite = &H40
ExecuteWriteCopy = &H80
Guard = &H100
NoCache = &H200
WriteCombine = &H400
End Enum
Public Enum ChildWindowFromPointFlags As UInteger
CWP_ALL
CWP_SKIPINVISIBLE
CWP_SKIPDISABLED
CWP_SKIPTRANSPARENT
End Enum
<StructLayout(LayoutKind.Sequential)>
Public Structure WINDOWPOS
Public hwnd As IntPtr
Public hwndInsertAfter As IntPtr
Public x As Integer
Public y As Integer
Public cx As Integer
Public cy As Integer
Public flags As Integer
End Structure
Public Structure RectangleAPI
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
Public Overrides Function ToString() As String
Return String.Format("Top: {0}, Bottom: {1}, Left: {2}, Right: {3}", Top, Bottom, Left, Right)
End Function
End Structure
Public Structure ShellExecuteInfo
Public cbSize As Integer
Public fMask As Integer
Public hwnd As IntPtr
<MarshalAs(UnmanagedType.LPTStr)> Public lpVerb As String
<MarshalAs(UnmanagedType.LPTStr)> Public lpFile As String
<MarshalAs(UnmanagedType.LPTStr)> Public lpParameters As String
<MarshalAs(UnmanagedType.LPTStr)> Public lpDirectory As String
Dim nShow As Integer
Dim hInstApp As IntPtr
Dim lpIDList As IntPtr
<MarshalAs(UnmanagedType.LPTStr)> Public lpClass As String
Public hkeyClass As IntPtr
Public dwHotKey As Integer
Public hIcon As IntPtr
Public hProcess As IntPtr
End Structure
<System.Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential)>
Public Structure PointAPI
Public X As Integer
Public Y As Integer
Public Sub New(ByVal X As Integer, ByVal Y As Integer)
Me.X = X
Me.Y = Y
End Sub
End Structure
End Class

46
Base/ObjectEx.vb Normal file
View File

@@ -0,0 +1,46 @@
Public Class ObjectEx
''' <summary>
''' Checks a value for three different `null` values,
''' Nothing, Empty String, DBNull
'''
''' Returns the original value if the value is not null, or `defaultValue`
''' </summary>
''' <typeparam name="T">The type of the value</typeparam>
''' <param name="value">The value</param>
''' <param name="defaultValue">The default Value</param>
''' <returns>The original value or the default value</returns>
Public Shared Function NotNull(Of T)(ByVal value As T, ByVal defaultValue As T) As T
If IsNothing(value) OrElse String.IsNullOrEmpty(value.ToString) OrElse IsDBNull(value) Then
Return defaultValue
Else
Return value
End If
End Function
''' <summary>
''' Converts a String value to the given Enum
''' </summary>
''' <typeparam name="T">The Enum Type</typeparam>
''' <param name="value">The string value to convert</param>
Public Shared Function ToEnum(Of T)(value As String) As T
Return [Enum].Parse(GetType(T), value)
End Function
''' <summary>
''' Converts an Integer value to the given Enum
''' </summary>
''' <typeparam name="T">The Enum Type</typeparam>
''' <param name="value">The integer value to convert</param>
Public Shared Function ToEnum(Of T)(value As Integer) As T
Return [Enum].ToObject(GetType(T), value)
End Function
''' <summary>
''' Converts a Long value to the given Enum
''' </summary>
''' <typeparam name="T">The Enum Type</typeparam>
''' <param name="value">The long value to convert</param>
Public Shared Function ToEnum(Of T)(value As Long) As T
Return [Enum].ToObject(GetType(T), value)
End Function
End Class

View File

@@ -1,44 +0,0 @@
Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Security.Cryptography
Imports DigitalData.Modules.Logging
Public Class Performance
Public Sub New(pLogConfig As LogConfig, pAppDataPath As String)
Dim savedHash = String.Empty
Dim assemblyLocation = Assembly.GetEntryAssembly().Location
Dim hashPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "hash.txt")
If Not File.Exists(hashPath) Then
File.Create(hashPath)
Else
savedHash = File.ReadAllText(hashPath)
End If
Dim hash = String.Concat(SHA1.Create().ComputeHash(File.ReadAllBytes(assemblyLocation)).Select(Function(x) x.ToString("x2")))
If hash.Equals(savedHash) Then
Return
End If
Dim dotNetRuntimePath = RuntimeEnvironment.GetRuntimeDirectory()
Dim ngenPath = Path.Combine(dotNetRuntimePath, "ngen.exe")
Dim process = New Process With {
.StartInfo = New ProcessStartInfo With {
.FileName = ngenPath,
.Arguments = $"install ""{assemblyLocation}"" /nologo",
.CreateNoWindow = True,
.UseShellExecute = True,
.Verb = "runas"
}
}
Try
process.Start()
process.WaitForExit()
File.WriteAllText(hashPath, hash)
Catch
' ...
End Try
End Sub
End Class

163
Base/ScreenEx.vb Normal file
View File

@@ -0,0 +1,163 @@
Imports System
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports DigitalData.Modules.Base.NativeMethods
Public Class ScreenEx
Public Const DEFAULT_WINDOW_HEIGHT = 480
Public Const DEFAULT_WINDOW_WIDTH = 640
Friend Const MONITORINFOF_PRIMARY As Integer = &H1
Friend Const MONITOR_DEFAULTTONEAREST As Integer = &H2
Friend Const MONITOR_DEFAULTTONULL As Integer = &H0
Friend Const MONITOR_DEFAULTTOPRIMARY As Integer = &H1
Friend Enum Monitor_DPI_Type As Integer
MDT_Effective_DPI = 0
MDT_Angular_DPI = 1
MDT_Raw_DPI = 2
MDT_Default = MDT_Effective_DPI
End Enum
Private Enum DeviceCap
VERTRES = 10
DESKTOPVERTRES = 117
End Enum
Public Shared Function GetLocationWithinScreen(pLocation As Point) As Point?
For Each screen As Screen In Screen.AllScreens
If screen.Bounds.Contains(pLocation) Then
Return New Point(pLocation.X - screen.Bounds.Left, pLocation.Y - screen.Bounds.Top)
End If
Next
Return Nothing
End Function
Public Shared Sub RestoreFormPosition(pForm As Form, pPosition As Point)
Dim oLocationWithinScreen As Point? = GetLocationWithinScreen(pPosition)
If oLocationWithinScreen Is Nothing Then
Dim oPrimaryScreen = Screen.PrimaryScreen
pForm.StartPosition = FormStartPosition.CenterScreen
Else
pForm.StartPosition = FormStartPosition.Manual
pForm.Location = pPosition
End If
End Sub
Public Shared Sub RestoreFormState(pForm As Form, pFormState As FormWindowState)
If pFormState = FormWindowState.Maximized Then
pForm.WindowState = FormWindowState.Normal
pForm.WindowState = FormWindowState.Maximized
ElseIf pFormState = FormWindowState.Minimized Then
pForm.WindowState = FormWindowState.Normal
pForm.WindowState = FormWindowState.Minimized
Else
pForm.WindowState = FormWindowState.Normal
End If
End Sub
Public Shared Sub RestoreFormState(pForm As Form, pFormState As String)
Dim oFormState As FormWindowState
If Not [Enum].TryParse(pFormState, oFormState) Then
oFormState = FormWindowState.Normal
End If
RestoreFormState(pForm, oFormState)
End Sub
Public Shared Sub RestoreFormSize(pForm As Form, pFormSize As Size)
Dim oFormSize As Size
If pFormSize.Height < 1 Or pFormSize.Width < 1 Or pFormSize.IsEmpty Then
oFormSize = New Size(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT)
Else
oFormSize = pFormSize
End If
pForm.Size = oFormSize
End Sub
''' <summary>
''' Checks if a point is Visible on any screen
''' </summary>
Public Shared Function IsVisibleOnAnyScreen(Location As Point) As Boolean
Try
Dim oRect As New Rectangle(Location, New Size(0, 0))
For Each oScreen In Screen.AllScreens
If oScreen.WorkingArea.IntersectsWith(oRect) Then
Return True
End If
Next
Return False
Catch ex As Exception
Return False
End Try
End Function
''' <summary>
''' Checks if Size is not negative
''' </summary>
Public Shared Function SizeIsVisible(Size As Size) As Boolean
If Size.Width >= 0 And Size.Height >= 0 Then
Return True
End If
Return False
End Function
''' <summary>
''' Checks if Location is not negative
''' </summary>
Public Shared Function LocationIsVisible(Location As Point) As Boolean
If Location.X >= 0 And Location.Y >= 0 Then
Return True
End If
Return False
End Function
Public Function GetScreenScaling(Form As Form) As Single
Dim oHandle As IntPtr = Form.Handle
Dim oFactor1, oFactor2 As Single
oFactor1 = GetFactorFromDeviceCaps(oHandle)
oFactor2 = GetDPIFromMonitor(oHandle)
If oFactor1 > 1 Then
Return oFactor1
Else
Return oFactor2
End If
End Function
Private Function GetFactorFromDeviceCaps(Handle As IntPtr) As Single
Dim g As Graphics = Graphics.FromHwnd(Handle)
Dim desktop As IntPtr = g.GetHdc()
Dim LogicalScreenHeight As Integer = GetDeviceCaps(desktop, DeviceCap.VERTRES)
Dim PhysicalScreenHeight As Integer = GetDeviceCaps(desktop, DeviceCap.DESKTOPVERTRES)
Dim oScreenScalingFactor As Single = CSng(PhysicalScreenHeight) / CSng(LogicalScreenHeight)
Return oScreenScalingFactor
End Function
Private Function GetDPIFromMonitor(Handle As IntPtr) As Single
'Get handle to monitor that contains this window.
Dim monitorHandle As IntPtr = MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST)
'Get DPI (If the OS is not Windows 8.1 or newer, calling GetDpiForMonitor will cause exception).
Dim dpiX As UInteger
Dim dpiY As UInteger
Dim result As Integer = GetDpiForMonitor(monitorHandle, Monitor_DPI_Type.MDT_Default, dpiX, dpiY)
If (result = 0) Then 'If S_OK (= 0)
Return dpiX / 96.0F
Else
Return -1
End If
End Function
End Class

141
Base/StringEx.vb Normal file

File diff suppressed because one or more lines are too long

36
Base/WindowsEx.vb Normal file
View File

@@ -0,0 +1,36 @@
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Base.NativeMethods
Public Class WindowsEx
Private ReadOnly _LogConfig As LogConfig
Private ReadOnly _Logger As Logger
Public Sub New(LogConfig As LogConfig)
_LogConfig = LogConfig
_Logger = LogConfig.GetLogger()
End Sub
Public Function OpenFileProperties(FilePath As String) As Boolean
Try
Dim oShellExecuteInfo As New ShellExecuteInfo()
oShellExecuteInfo.cbSize = Marshal.SizeOf(oShellExecuteInfo)
oShellExecuteInfo.lpVerb = "properties"
oShellExecuteInfo.lpFile = FilePath
oShellExecuteInfo.nShow = SW_SHOW
oShellExecuteInfo.fMask = SEE_MASK_INVOKEIDLIST
If Not ShellExecuteEx(oShellExecuteInfo) Then
Dim oWin32Error = Marshal.GetLastWin32Error()
Dim oException As New Win32Exception(oWin32Error)
Throw oException
End If
Return True
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
End Function
End Class

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="NLog" version="5.0.5" targetFramework="net461" />
</packages>

View File

@@ -10,7 +10,8 @@
<AssemblyName>DigitalData.Modules.Config</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -43,9 +44,12 @@
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<ItemGroup>
<Reference Include="DigitalData.Modules.Base">
<HintPath>..\Base\bin\Debug\DigitalData.Modules.Base.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@@ -81,6 +85,7 @@
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
@@ -118,10 +123,6 @@
<Project>{8a8f20fc-c46e-41ac-bee7-218366cfff99}</Project>
<Name>Encryption</Name>
</ProjectReference>
<ProjectReference Include="..\Filesystem\Filesystem.vbproj">
<Project>{991d0231-4623-496d-8bd0-9ca906029cbc}</Project>
<Name>Filesystem</Name>
</ProjectReference>
<ProjectReference Include="..\Logging\Logging.vbproj">
<Project>{903b2d7d-3b80-4be9-8713-7447b704e1b0}</Project>
<Name>Logging</Name>

View File

@@ -2,17 +2,17 @@
Imports System.Reflection
Imports System.Xml.Serialization
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Encryption
Imports DigitalData.Modules.Config.ConfigAttributes
Imports DigitalData.Modules.Base
Public Class ConfigManager(Of T)
Private Const USER_CONFIG_NAME As String = "UserConfig.xml"
Private Const COMPUTER_CONFIG_NAME As String = "ComputerConfig.xml"
Private Const APP_CONFIG_NAME As String = "AppConfig.xml"
Public Const USER_CONFIG_NAME As String = "UserConfig.xml"
Public Const COMPUTER_CONFIG_NAME As String = "ComputerConfig.xml"
Public Const APP_CONFIG_NAME As String = "AppConfig.xml"
Private ReadOnly _LogConfig As LogConfig
Private ReadOnly _Logger As Logger
Private ReadOnly _File As Filesystem.File
Private ReadOnly _File As FilesystemEx
Private ReadOnly _UserDirectory As String
Private ReadOnly _UserConfigPath As String
@@ -104,7 +104,7 @@ Public Class ConfigManager(Of T)
Public Sub New(LogConfig As LogConfig, UserConfigPath As String, ComputerConfigPath As String, Optional ApplicationStartupPath As String = "", Optional ForceUserConfig As Boolean = False)
_LogConfig = LogConfig
_Logger = LogConfig.GetLogger()
_File = New Filesystem.File(_LogConfig)
_File = New FilesystemEx(_LogConfig)
_Blueprint = Activator.CreateInstance(Of T)
_BlueprintType = _Blueprint.GetType
@@ -122,9 +122,9 @@ Public Class ConfigManager(Of T)
_ComputerConfigPath = Path.Combine(_ComputerDirectory, COMPUTER_CONFIG_NAME)
End If
If ApplicationStartupPath <> String.Empty Then
_Logger.Info($"AppConfig is being used: [{ApplicationStartupPath}]")
If ApplicationStartupPath <> String.Empty Then
_AppConfigPath = Path.Combine(ApplicationStartupPath, APP_CONFIG_NAME)
End If
_WriteAllValuesToUserConfig = ForceUserConfig

View File

@@ -1,17 +1,80 @@
Imports DigitalData.Modules.Logging
Imports System.IO
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Logging
Public Class ConfigUtils
Private _Logger As Logger
Private _File As Filesystem.File
Private ReadOnly _Logger As Logger
Private ReadOnly _File As FilesystemEx
Private Const MIGRATE_DIRECTORY As String = "Migrate"
Public Sub New(LogConfig As LogConfig)
_Logger = LogConfig.GetLogger()
_File = New Filesystem.File(LogConfig)
_File = New FilesystemEx(LogConfig)
End Sub
''' <summary>
''' Migrate a config file when the ProductName has changed
''' </summary>
''' <param name="pUserBasePath">The user config base path, should be Application.UserAppDataPath</param>
''' <param name="pProductName">The current or new product name</param>
''' <param name="pOldProductName">The old product name</param>
''' <returns></returns>
Public Function MigrateUserAppDataConfig(pUserBasePath As String, pProductName As String, pOldProductName As String)
Return MigrateAppDataConfig(pUserBasePath, ConfigManager(Of ConfigSample).USER_CONFIG_NAME, pProductName, pOldProductName)
End Function
''' <summary>
''' Migrate a config file when the ProductName has changed
''' </summary>
''' <param name="pCommonBasePath">The config base path, should be Application.CommonAppDataPath</param>
''' <param name="pProductName">The current or new product name</param>
''' <param name="pOldProductName">The old product name</param>
''' <returns></returns>
Public Function MigrateCommonAppDataConfig(pCommonBasePath As String, pProductName As String, pOldProductName As String)
Return MigrateAppDataConfig(pCommonBasePath, ConfigManager(Of ConfigSample).COMPUTER_CONFIG_NAME, pProductName, pOldProductName)
End Function
''' <summary>
''' Migrate a config file when the ProductName has changed
''' </summary>
''' <param name="pBasePath">The config base path, can be Application.UserAppDataPath or Application.CommonAppDataPath</param>
''' <param name="pProductName">The current or new product name</param>
''' <param name="pOldProductName">The old product name</param>
''' <returns></returns>
Private Function MigrateAppDataConfig(pBasePath As String, pConfigName As String, pProductName As String, pOldProductName As String)
Dim oNewDirPath = pBasePath
Dim oOldDirPath = oNewDirPath.Replace(pProductName, pOldProductName)
Dim oNewFilePath = Path.Combine(oNewDirPath, pConfigName)
Dim oOldFilePath = Path.Combine(oOldDirPath, pConfigName)
' If there is already a new config, exit.
If File.Exists(oNewFilePath) Then
Return True
End If
' If there is no old config, exit.
If Not File.Exists(oOldFilePath) Then
Return True
End If
Try
If Not Directory.Exists(oNewDirPath) Then
Directory.CreateDirectory(oNewDirPath)
End If
_Logger.Info("Migrating Config from [{0}] to [{1}]", pOldProductName, pProductName)
File.Move(oOldFilePath, oNewFilePath)
Return True
Catch ex As Exception
_Logger.Warn("Error while Migrating Config")
_Logger.Error(ex)
Return False
End Try
End Function
Public Function TestMigrationNeeded(TargetDirectory As String) As Boolean
If IO.Directory.Exists(TargetDirectory) Then
Return False
@@ -21,99 +84,97 @@ Public Class ConfigUtils
End Function
Public Sub MigrateConfig(SourceDirectory As String, TargetDirectory As String, Optional FilePattern As String = "*.*")
If IO.Directory.Exists(TargetDirectory) Then
_Logger.Warn("Config Migration aborted because new config directory [{0}] already exists!", TargetDirectory)
Exit Sub
End If
'If IO.Directory.Exists(TargetDirectory) Then
' _Logger.Warn("Config Migration aborted because new config directory [{0}] already exists!", TargetDirectory)
' Exit Sub
'End If
_Logger.Debug("Creating TargetDirectory [{0}]", TargetDirectory)
' Create target directory
Try
IO.Directory.CreateDirectory(TargetDirectory)
Catch ex As Exception
_Logger.Warn("Config Migration aborted because new config directory [{0}] could not be created!", TargetDirectory)
_Logger.Error(ex)
Exit Sub
End Try
'_Logger.Debug("Creating TargetDirectory [{0}]", TargetDirectory)
'' Create target directory
'Try
' IO.Directory.CreateDirectory(TargetDirectory)
'Catch ex As Exception
' _Logger.Warn("Config Migration aborted because new config directory [{0}] could not be created!", TargetDirectory)
' _Logger.Error(ex)
' Exit Sub
'End Try
' Create Migration directory
Dim oMigrationDirectory = IO.Path.Combine(SourceDirectory, MIGRATE_DIRECTORY)
_Logger.Debug("Creating MigrationDirectory [{0}]", oMigrationDirectory)
Try
IO.Directory.CreateDirectory(oMigrationDirectory)
Catch ex As Exception
_Logger.Warn("Config Migration aborted because migration directory [{0}] could not be created!", oMigrationDirectory)
_Logger.Error(ex)
Exit Sub
End Try
'' Create Migration directory
'Dim oMigrationDirectory = IO.Path.Combine(SourceDirectory, MIGRATE_DIRECTORY)
'_Logger.Debug("Creating MigrationDirectory [{0}]", oMigrationDirectory)
'Try
' IO.Directory.CreateDirectory(oMigrationDirectory)
'Catch ex As Exception
' _Logger.Warn("Config Migration aborted because migration directory [{0}] could not be created!", oMigrationDirectory)
' _Logger.Error(ex)
' Exit Sub
'End Try
' Copy individual files from top level directory
For Each oPath In IO.Directory.EnumerateFiles(SourceDirectory, FilePattern)
Dim oFileInfo = New IO.FileInfo(oPath)
'' Copy individual files from top level directory
'For Each oPath In IO.Directory.EnumerateFiles(SourceDirectory, FilePattern)
' Dim oFileInfo = New IO.FileInfo(oPath)
_Logger.NewBlock($"File {oFileInfo.Name}")
_Logger.Debug("Processing file [{0}]", oFileInfo.Name)
' _Logger.Debug("Processing file [{0}]", oFileInfo.Name)
_Logger.Debug("Copying [{0}] to TargetDirectory..", oFileInfo.Name)
' Copy to target directory
Try
IO.File.Copy(oPath, IO.Path.Combine(TargetDirectory, oFileInfo.Name))
Catch ex As Exception
_Logger.Warn("Could not move old config file {0} to new config location {1}", oFileInfo.Name, TargetDirectory)
_Logger.Error(ex)
End Try
' _Logger.Debug("Copying [{0}] to TargetDirectory..", oFileInfo.Name)
' ' Copy to target directory
' Try
' IO.File.Copy(oPath, IO.Path.Combine(TargetDirectory, oFileInfo.Name))
' Catch ex As Exception
' _Logger.Warn("Could not move old config file {0} to new config location {1}", oFileInfo.Name, TargetDirectory)
' _Logger.Error(ex)
' End Try
_Logger.Debug("Moving [{0}] to MigrationDirectory..", oFileInfo.Name)
' Move to migration directory
Try
IO.File.Move(oPath, IO.Path.Combine(oMigrationDirectory, oFileInfo.Name))
Catch ex As Exception
_Logger.Warn("Could not move old config file {0} to migration directory {1}", oFileInfo.Name, oMigrationDirectory)
_Logger.Error(ex)
End Try
Next
' _Logger.Debug("Moving [{0}] to MigrationDirectory..", oFileInfo.Name)
' ' Move to migration directory
' Try
' IO.File.Move(oPath, IO.Path.Combine(oMigrationDirectory, oFileInfo.Name))
' Catch ex As Exception
' _Logger.Warn("Could not move old config file {0} to migration directory {1}", oFileInfo.Name, oMigrationDirectory)
' _Logger.Error(ex)
' End Try
'Next
For Each oDirectoryPath In IO.Directory.EnumerateDirectories(SourceDirectory, "*", IO.SearchOption.TopDirectoryOnly)
Dim oDirInfo As New IO.DirectoryInfo(oDirectoryPath)
'For Each oDirectoryPath In IO.Directory.EnumerateDirectories(SourceDirectory, "*", IO.SearchOption.TopDirectoryOnly)
' Dim oDirInfo As New IO.DirectoryInfo(oDirectoryPath)
_Logger.NewBlock($"Directory {oDirInfo.Name}")
_Logger.Debug("Processing directory [{0}]", oDirInfo.Name)
' _Logger.Debug("Processing directory [{0}]", oDirInfo.Name)
' Don't copy TargetDirectory if subpath of SourceDirectory or if MigrationDirectory
If oDirInfo.FullName = TargetDirectory Or oDirInfo.FullName = oMigrationDirectory Then
_Logger.Debug("Directory [{0}] should not be copied. Skipping.", oDirInfo.Name)
Continue For
End If
' ' Don't copy TargetDirectory if subpath of SourceDirectory or if MigrationDirectory
' If oDirInfo.FullName = TargetDirectory Or oDirInfo.FullName = oMigrationDirectory Then
' _Logger.Debug("Directory [{0}] should not be copied. Skipping.", oDirInfo.Name)
' Continue For
' End If
' Copy directory to TargetDirectory
Dim oNewDirectoryPath = IO.Path.Combine(TargetDirectory, oDirInfo.Name)
_Logger.Debug("Copying [{0}] to TargetDirectory..", oDirInfo.Name)
Try
_File.CopyDirectory(oDirInfo.FullName, oNewDirectoryPath, True)
Catch ex As Exception
_Logger.Warn("Could not move directory [{0}] to new path [{1}]", oDirInfo.FullName, oNewDirectoryPath)
_Logger.Error(ex)
End Try
' ' Copy directory to TargetDirectory
' Dim oNewDirectoryPath = IO.Path.Combine(TargetDirectory, oDirInfo.Name)
' _Logger.Debug("Copying [{0}] to TargetDirectory..", oDirInfo.Name)
' Try
' _File.CopyDirectory(oDirInfo.FullName, oNewDirectoryPath, True)
' Catch ex As Exception
' _Logger.Warn("Could not move directory [{0}] to new path [{1}]", oDirInfo.FullName, oNewDirectoryPath)
' _Logger.Error(ex)
' End Try
_Logger.Debug("Copying [{0}] to MigrationDirectory..", oDirInfo.Name)
' Copy directory to MigrationDirectory
Dim oMigrationDirectoryPath = IO.Path.Combine(oMigrationDirectory, oDirInfo.Name)
Try
_File.CopyDirectory(oDirInfo.FullName, oMigrationDirectoryPath, True)
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn("Could not move directory [{0}] to migration directory [{1}]", oDirInfo.FullName, oMigrationDirectoryPath)
End Try
' _Logger.Debug("Copying [{0}] to MigrationDirectory..", oDirInfo.Name)
' ' Copy directory to MigrationDirectory
' Dim oMigrationDirectoryPath = IO.Path.Combine(oMigrationDirectory, oDirInfo.Name)
' Try
' _File.CopyDirectory(oDirInfo.FullName, oMigrationDirectoryPath, True)
' Catch ex As Exception
' _Logger.Error(ex)
' _Logger.Warn("Could not move directory [{0}] to migration directory [{1}]", oDirInfo.FullName, oMigrationDirectoryPath)
' End Try
_Logger.Debug("Deleting [{0}]..", oDirInfo.Name)
' Delete directory
Try
IO.Directory.Delete(oDirInfo.FullName, True)
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn("Could not delete directory [{0}]", oDirInfo.FullName)
End Try
Next
' _Logger.Debug("Deleting [{0}]..", oDirInfo.Name)
' ' Delete directory
' Try
' IO.Directory.Delete(oDirInfo.FullName, True)
' Catch ex As Exception
' _Logger.Error(ex)
' _Logger.Warn("Could not delete directory [{0}]", oDirInfo.FullName)
' End Try
'Next
End Sub
End Class

View File

@@ -12,7 +12,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("Modules.Config")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyCopyright("Copyright © 2023")>
<Assembly: AssemblyTrademark("")>
<Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.1.4.1")>
<Assembly: AssemblyFileVersion("1.1.4.1")>
<Assembly: AssemblyVersion("1.2.2.0")>
<Assembly: AssemblyFileVersion("1.2.2.0")>

View File

@@ -22,7 +22,7 @@ Namespace My.Resources
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0"), _
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _

View File

@@ -15,7 +15,7 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="NLog" version="5.0.5" targetFramework="net461" />
</packages>

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MySubMain>false</MySubMain>
<MySubMain>true</MySubMain>
<MainForm>Form1</MainForm>
<SingleInstance>false</SingleInstance>
<ShutdownMode>0</ShutdownMode>
<EnableVisualStyles>true</EnableVisualStyles>
<AuthenticationMode>0</AuthenticationMode>
<ApplicationType>1</ApplicationType>
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
</MyApplicationData>
</MyApplicationData>

View File

@@ -1,16 +1,22 @@
Imports System.ComponentModel
Imports System.Data.Common
Imports System.Data.SqlClient
Imports DigitalData.Modules.Encryption
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Base
Imports System.Threading
Public Class MSSQLServer
Implements IDatabase
Public Property DBInitialized As Boolean = False Implements IDatabase.DBInitialized
Public Property CurrentConnectionString As String = "" Implements IDatabase.CurrentConnectionString
Public ReadOnly Property MaskedConnectionString As String
Get
If CurrentConnectionString = "" Then
Return ""
Else
Return MaskConnectionString(CurrentConnectionString)
End If
End Get
End Property
Private ReadOnly QueryTimeout As Integer
Private ReadOnly Logger As Logger
@@ -103,33 +109,34 @@ Public Class MSSQLServer
End Try
End Function
<DebuggerStepThrough()>
Private Function MaybeGetTransaction(Connection As SqlConnection, Mode As TransactionMode, Transaction As SqlTransaction) As SqlTransaction
If Connection Is Nothing Then
Throw New ArgumentNullException("Connection")
Private Function MaybeGetTransaction(pConnection As SqlConnection, pTransactionMode As TransactionMode, pTransaction As SqlTransaction) As SqlTransaction
If pConnection Is Nothing Then
Throw New ArgumentNullException("Connection", "Could not get transaction because connection is null!")
End If
If Mode = TransactionMode.NoTransaction Then
Logger.Debug("Transaction Mode: [{0}]", pTransactionMode.ToString)
If pTransactionMode = TransactionMode.NoTransaction Then
Return Nothing
ElseIf Mode = TransactionMode.ExternalTransaction Then
Return Transaction
ElseIf pTransactionMode = TransactionMode.ExternalTransaction Then
Return pTransaction
Else
Return Connection.BeginTransaction()
Return pConnection.BeginTransaction()
End If
End Function
<DebuggerStepThrough()>
Private Function MaybeCommitTransaction(Transaction As SqlTransaction, TransactionMode As TransactionMode) As Boolean
Select Case TransactionMode
Private Function MaybeCommitTransaction(pTransaction As SqlTransaction, pTransactionMode As TransactionMode) As Boolean
Select Case pTransactionMode
Case TransactionMode.NoTransaction
Return True
Case TransactionMode.ExternalTransaction
Return True
Case TransactionMode.WithTransaction
Try
Transaction.Commit()
pTransaction.Commit()
Return True
Catch ex As Exception
Logger.Warn("Error while committing transaction!")
Logger.Error(ex)
Return False
End Try
@@ -206,10 +213,13 @@ Public Class MSSQLServer
Dim oDecryptedConnectionString = DecryptConnectionString(pConnectionString)
Dim oConnection As New SqlConnection(oDecryptedConnectionString)
OpenSQLConnection(oConnection)
oConnection.Close()
oConnection?.Close()
Return True
Catch ex As Exception
Logger.Error("Error while testing connection!")
Logger.Error(ex)
Return False
End Try
End Function
@@ -217,14 +227,21 @@ Public Class MSSQLServer
''' <summary>
''' This Function intentionally has no try..catch block to have any errors caught outside
''' </summary>
''' <param name="Connection"></param>
''' <param name="pConnection"></param>
''' <returns></returns>
Private Function OpenSQLConnection(Connection As SqlConnection) As SqlConnection
If Connection.State = ConnectionState.Closed Then
Connection.Open()
End If
Private Function OpenSQLConnection(pConnection As SqlConnection) As SqlConnection
Try
If pConnection.State = ConnectionState.Closed Then
pConnection.Open()
End If
Return Connection
Return pConnection
Catch ex As Exception
Logger.Error("Error while opening Connection!")
Logger.Error(ex)
Throw ex
End Try
End Function
<DebuggerStepThrough()>
@@ -242,6 +259,7 @@ Public Class MSSQLServer
Return oConnection
Catch ex As Exception
Logger.Error("Connection could not be created or opened!")
Logger.Error(ex)
Return Nothing
@@ -253,14 +271,16 @@ Public Class MSSQLServer
Try
If pConnectionString Is Nothing OrElse pConnectionString.Length = 0 Then
Logger.Warn("Connection String is empty!")
Throw New ArgumentNullException("pConnectionString")
Throw New ArgumentNullException("pConnectionString", "Could not mask connection string because connectiong string is empty!")
End If
Dim oBuilder As New SqlConnectionStringBuilder() With {.ConnectionString = pConnectionString}
Dim oConnectionString = pConnectionString.Replace(oBuilder.Password, "XXXXX")
Return oConnectionString
Catch ex As Exception
Logger.Error("ConnectionString is invalid and could not be masked!")
Logger.Error(ex)
Return "Invalid ConnectionString"
End Try
End Function
@@ -288,15 +308,11 @@ Public Class MSSQLServer
End Function
Public Function GetDatatable(pSqlCommand As String, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable
Using oSqlConnection = GetSQLConnection()
Return GetDatatableWithConnectionObject(pSqlCommand, oSqlConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Using
Return GetDatatableWithConnectionObject(pSqlCommand, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Function
Public Function GetDatatable(pSqlCommandObject As SqlCommand, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable
Using oSqlConnection = GetSQLConnection()
Return GetDatatableWithConnectionObject(pSqlCommandObject, oSqlConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Using
Return GetDatatableWithConnectionObject(pSqlCommandObject, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Function
Public Async Function GetDatatableAsync(pSqlCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of DataTable)
@@ -319,6 +335,20 @@ Public Class MSSQLServer
End Using
End Function
Public Async Function GetDatatableWithConnectionObjectAsync(pSqlCommand As String, pSqlConnection As SqlConnection,
Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional pTransaction As SqlTransaction = Nothing,
Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of DataTable)
Return Await Task.Run(Function() GetDatatableWithConnectionObject(pSqlCommand, pSqlConnection, pTransactionMode, pTransaction, pTimeout))
End Function
Public Async Function GetDatatableWithConnectionObjectAsync(pSqlCommandObject As SqlCommand, pSqlConnection As SqlConnection,
Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional pTransaction As SqlTransaction = Nothing,
Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of DataTable)
Return Await Task.Run(Function() GetDatatableWithConnectionObject(pSqlCommandObject, pSqlConnection, pTransactionMode, pTransaction, pTimeout))
End Function
Public Function GetDatatableWithConnectionObject(pSqlCommand As String, pSqlConnection As SqlConnection,
Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional pTransaction As SqlTransaction = Nothing,
@@ -340,13 +370,13 @@ Public Class MSSQLServer
pSqlCommandObject.CommandTimeout = pTimeout
Using oAdapter As New SqlDataAdapter(pSqlCommandObject)
Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", pSqlCommandObject.CommandText)
Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}] and Parameters [{1}]", pSqlCommandObject.CommandText, GetParameterListAsString(pSqlCommandObject))
oAdapter.Fill(oTable)
End Using
Catch ex As Exception
Logger.Error("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", pSqlCommandObject.CommandText)
Logger.Error(ex)
Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", pSqlCommandObject)
Throw ex
Finally
MaybeCommitTransaction(oTransaction, pTransactionMode)
@@ -381,15 +411,11 @@ Public Class MSSQLServer
Public Function ExecuteNonQuery(pSQLCommand As String, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean
Using oConnection = GetSQLConnection()
Return ExecuteNonQueryWithConnectionObject(pSQLCommand, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Using
Return ExecuteNonQueryWithConnectionObject(pSQLCommand, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Function
Public Function ExecuteNonQuery(pSQLCommandObject As SqlCommand, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean
Using oConnection = GetSQLConnection()
Return ExecuteNonQueryWithConnectionObject(pSQLCommandObject, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Using
Return ExecuteNonQueryWithConnectionObject(pSQLCommandObject, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Function
Public Async Function ExecuteNonQueryAsync(pSQLCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Boolean)
@@ -427,7 +453,7 @@ Public Class MSSQLServer
Dim oTransaction As SqlTransaction = MaybeGetTransaction(pSqlConnection, pTransactionMode, pTransaction)
Try
Logger.Debug("ExecuteNonQueryWithConnectionObject: Running Command [{0}]", pSqlCommandObject.CommandText)
Logger.Debug("ExecuteNonQueryWithConnectionObject: Running Command [{0}] and Parameters [{1}]", pSqlCommandObject.CommandText, GetParameterListAsString(pSqlCommandObject))
pSqlCommandObject.Connection = pSqlConnection
pSqlCommandObject.Transaction = oTransaction
@@ -436,8 +462,9 @@ Public Class MSSQLServer
Return True
Catch ex As Exception
Logger.Error("ExecuteNonQueryWithConnectionObject: Error in ExecuteNonQueryWithConnectionObject while executing command: [{0}]", pSqlCommandObject.CommandText)
Logger.Error(ex)
Logger.Warn("ExecuteNonQueryWithConnectionObject: Error in ExecuteNonQueryWithConnectionObject while executing command: [{0}]-[{1}]", SqlCommand, SqlConnection.ConnectionString)
Return False
Finally
MaybeCommitTransaction(oTransaction, pTransactionMode)
@@ -469,15 +496,11 @@ Public Class MSSQLServer
End Function
Public Function GetScalarValue(pSQLCommand As String, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object
Using oConnection = GetSQLConnection()
Return GetScalarValueWithConnectionObject(pSQLCommand, oConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Using
Return GetScalarValueWithConnectionObject(pSQLCommand, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Function
Public Function GetScalarValue(pSQLCommandObject As SqlCommand, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object
Using oConnection = GetSQLConnection()
Return GetScalarValueWithConnectionObject(pSQLCommandObject, oConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Using
Return GetScalarValueWithConnectionObject(pSQLCommandObject, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout)
End Function
Public Async Function GetScalarValueAsync(pSQLCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Object)
@@ -517,6 +540,9 @@ Public Class MSSQLServer
Dim oResult As Object = Nothing
Try
Logger.Debug("GetScalarValueWithConnectionObject: Running Query [{0}] with Parameters [{1}]", pSqlCommandObject.CommandText, GetParameterListAsString(pSqlCommandObject))
pSqlCommandObject.Connection = pSqlConnection
pSqlCommandObject.CommandTimeout = pTimeout
pSqlCommandObject.Transaction = oTransaction
@@ -524,7 +550,7 @@ Public Class MSSQLServer
Catch ex As Exception
Logger.Error(ex)
Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", pSqlCommandObject)
Logger.Error("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", pSqlCommandObject.CommandText)
Finally
MaybeCommitTransaction(oTransaction, pTransactionMode)
@@ -559,7 +585,7 @@ Public Class MSSQLServer
End Using
Catch ex As Exception
Logger.Error(ex)
Logger.Warn($"GetScalarValue failed SQLCommand [{pSqlCommand}]")
Logger.Error($"GetScalarValue failed SQLCommand [{pSqlCommand}]")
Return Nothing
End Try
@@ -591,7 +617,7 @@ Public Class MSSQLServer
End Using
Catch ex As Exception
Logger.Error(ex)
Logger.Warn($"NewExecuteNonQueryAsync failed SQLCommand [{SqlCommand}]")
Logger.Error($"NewExecuteNonQueryAsync failed SQLCommand [{SqlCommand}]")
End Try
End Sub
@@ -601,4 +627,13 @@ Public Class MSSQLServer
Dim res = command.EndExecuteNonQuery(result)
Logger.Info("Finished executing Async database operation: {0}", command.CommandText)
End Sub
Private Function GetParameterListAsString(pSQLCommand As SqlCommand) As String
Dim oList = pSQLCommand.Parameters.
Cast(Of SqlParameter).
Select(Function(p) $"({p.ParameterName}={p.Value})").
ToList()
Return String.Join(",", oList)
End Function
End Class

View File

@@ -127,7 +127,7 @@ Public Class Oracle
End Try
End Function
Public Function GetDatatable(pSQLCommand As String, pTimeout As Integer) As DataTable Implements IDatabase.GetDatatable
Public Function GetDatatable(pSQLCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable Implements IDatabase.GetDatatable
Try
Using oConnection = GetConnection(CurrentConnectionString)
Dim oSQLCommand As OracleCommand
@@ -151,8 +151,8 @@ Public Class Oracle
End Try
End Function
Private Function GetDatatable(pSQLCommand As String) As DataTable Implements IDatabase.GetDatatable
Return GetDatatable(pSQLCommand, _Timeout)
Public Function GetDatatable(SqlCommand As SqlClient.SqlCommand, Optional Timeout As Integer = 120) As DataTable Implements IDatabase.GetDatatable
Throw New NotImplementedException()
End Function
Public Function ExecuteNonQuery(pSQLCommand As String, pTimeout As Integer) As Boolean Implements IDatabase.ExecuteNonQuery
@@ -250,4 +250,6 @@ Public Class Oracle
Return "Invalid ConnectionString"
End Try
End Function
End Class

View File

@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</configSections>
<entityFramework>
<defaultConnectionFactory type="EntityFramework.Firebird.FbConnectionFactory, EntityFramework.Firebird" />
<defaultConnectionFactory type="EntityFramework.Firebird.FbConnectionFactory, EntityFramework.Firebird"/>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="FirebirdSql.Data.FirebirdClient" type="EntityFramework.Firebird.FbProviderServices, EntityFramework.Firebird" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
<provider invariantName="FirebirdSql.Data.FirebirdClient" type="EntityFramework.Firebird.FbProviderServices, EntityFramework.Firebird"/>
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FirebirdSql.Data.FirebirdClient" publicKeyToken="3750abcc3150b00c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.5.0.0" newVersion="7.5.0.0" />
<assemblyIdentity name="FirebirdSql.Data.FirebirdClient" publicKeyToken="3750abcc3150b00c" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-7.5.0.0" newVersion="7.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration>

View File

@@ -11,9 +11,10 @@
<AssemblyName>DigitalData.Modules.Database</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -59,8 +60,8 @@
<HintPath>..\packages\FirebirdSql.Data.FirebirdClient.7.5.0\lib\net452\FirebirdSql.Data.FirebirdClient.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="Oracle.ManagedDataAccess">
<HintPath>P:\Visual Studio Projekte\Bibliotheken\Oracle.ManagedDataAccess.dll</HintPath>
@@ -99,7 +100,6 @@
<Compile Include="Dispatcher.vb" />
<Compile Include="Exceptions.vb" />
<Compile Include="Adapters\Firebird.vb" />
<Compile Include="Helpers.vb" />
<Compile Include="IDatabase.vb" />
<Compile Include="Adapters\ODBC.vb" />
<Compile Include="Adapters\Oracle.vb" />
@@ -108,6 +108,7 @@
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
@@ -120,7 +121,6 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Queries.vb" />
<Compile Include="TableCache.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">

View File

@@ -1,10 +0,0 @@
Public Class Helpers
Public Shared Function MaybeEscapeSQLCommand(pSQLCommand As String) As String
End Function
End Class

View File

@@ -12,8 +12,8 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("Digital Data")>
<Assembly: AssemblyProduct("Modules.Database")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("2.2.7.5")>
<Assembly: AssemblyCopyright("Copyright © 2024")>
<Assembly: AssemblyTrademark("2.3.4.0")>
<Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2.2.7.5")>
<Assembly: AssemblyFileVersion("2.2.7.5")>
<Assembly: AssemblyVersion("2.3.4.0")>
<Assembly: AssemblyFileVersion("2.3.4.0")>

View File

@@ -22,7 +22,7 @@ Namespace My.Resources
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0"), _
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _

View File

@@ -15,7 +15,7 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase

View File

@@ -1,17 +0,0 @@
Public Class TableCache
Private Items As New Dictionary(Of String, DataTable)
Public Function [Get](SQLCommand As String)
Dim oKey As String = SQLCommand.ToUpper
If Items.ContainsKey(oKey) Then
Return Items.Item(oKey)
Else
End If
End Function
Private Function SaveTable()
End Function
End Class

View File

@@ -3,6 +3,6 @@
<package id="EntityFramework" version="6.4.4" targetFramework="net461" />
<package id="EntityFramework.Firebird" version="6.4.0" targetFramework="net461" />
<package id="FirebirdSql.Data.FirebirdClient" version="7.5.0" targetFramework="net461" />
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="NLog" version="5.0.5" targetFramework="net461" />
<package id="System.Data.Odbc" version="6.0.1" targetFramework="net461" />
</packages>

View File

@@ -1,9 +1,9 @@
Imports System.IO
Imports System.ServiceModel
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.EDMI.API.Rights
Imports DigitalData.Modules.Language.Utils
Imports DigitalData.Modules.Logging
Public Class Client
@@ -550,10 +550,10 @@ Public Class Client
.Id = oRow.Item("AttributeId"),
.Title = oRow.Item("AttributeTitle"),
.Type = oRow.Item("AttributeType"),
.ValueBigInt = NotNull(oRow.Item("ValueBigInt"), Nothing),
.ValueDate = NotNull(oRow.Item("ValueDate"), Nothing),
.ValueDecimal = NotNull(oRow.Item("ValueDecimal"), Nothing),
.ValueText = NotNull(oRow.Item("ValueText"), Nothing)
.ValueBigInt = oRow.ItemEx(Of Object)("ValueBigInt", Nothing),
.ValueDate = oRow.ItemEx(Of Object)("ValueDate", Nothing),
.ValueDecimal = oRow.ItemEx(Of Object)("ValueDecimal", Nothing),
.ValueText = oRow.ItemEx(Of Object)("ValueText", Nothing)
}
oAttributes.Add(oAttribute)
@@ -932,11 +932,11 @@ Public Class Client
Private Function GetUserLanguage(pOverrideLanguage As String) As String
Return NotNull(pOverrideLanguage, Threading.Thread.CurrentThread.CurrentUICulture.Name)
Return ObjectEx.NotNull(pOverrideLanguage, Threading.Thread.CurrentThread.CurrentUICulture.Name)
End Function
Private Function GetUserName(pOverrideName) As String
Return NotNull(pOverrideName, Environment.UserName)
Return ObjectEx.NotNull(pOverrideName, Environment.UserName)
End Function
#End Region

View File

@@ -191,25 +191,30 @@ Public Class DatabaseWithFallback
' If there is no client, we assume there is no service (configured)
If _Client Is Nothing Then
_Logger.Debug("Client is empty, falling back to direct database access.")
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
End If
' If ForceFallback flag is set, we go to database immediately
If pForceFallback Or _ClientConfig.ForceDirectDatabaseAccess Then
_Logger.Debug("ForceFallback is True, falling back to direct database access.")
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
End If
' If the table is not cached, we try going through the service
If Not IsTableCached(pDataTableName) Then
_Logger.Debug("Datatable is not chached, fetching data from service.")
Return GetDatatableFromService(pFallbackSQL, pFallbackType, pConnectionId)
End If
' If there is a proper ConnectionId, we try going through the service
If pConnectionId > 0 Then
_Logger.Debug("ConnectionId is set, fetching data from service.")
Return GetDatatableFromService(pFallbackSQL, pFallbackType, pConnectionId)
End If
Try
_Logger.Debug("Datatable is chached, fetching data from cache.")
oTableResult = _Client.GetDatatableByName(pDataTableName, pFilterExpression, pSortByColumn)
Catch ex As Exception
_Logger.Error(ex)
@@ -332,26 +337,25 @@ Public Class DatabaseWithFallback
End Function
Private Function GetDatatableFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As DataTable
Private Function GetDatatableFromDatabase(pSQLCommand As String, pDatabaseType As Constants.DatabaseType, pConnectionId As Integer) As DataTable
Try
Dim oResult As ExecuteNonQueryResponse = Nothing
Select Case DatabaseType
Case Constants.DatabaseType.ECM
Return _DatabaseECM.GetDatatable(pSQLCommand)
_Logger.Debug("Fetching data from database [{0}] with Connection Id [{0}]", pDatabaseType.ToString, pConnectionId)
Select Case pDatabaseType
Case Constants.DatabaseType.IDB
Return _DatabaseIDB.GetDatatable(pSQLCommand)
Case Else
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
If oConnectionString = String.Empty Then
Return _DatabaseECM.GetDatatable(pSQLCommand)
Else
If pConnectionId > 0 Then
_Logger.Debug("Retrieving Connection String from Connection Id [{0}]", pConnectionId)
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
Return _DatabaseECM.GetDatatableWithConnection(pSQLCommand, oConnectionString)
Else
Return _DatabaseECM.GetDatatable(pSQLCommand)
End If
End Select
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
@@ -397,20 +401,19 @@ Public Class DatabaseWithFallback
Private Function GetScalarValueFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Object
Try
Select Case DatabaseType
Case Constants.DatabaseType.ECM
Return _DatabaseECM.GetScalarValue(pSQLCommand)
Case Constants.DatabaseType.IDB
Return _DatabaseIDB.GetScalarValue(pSQLCommand)
Case Else
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
If oConnectionString = String.Empty Then
Return _DatabaseECM.GetScalarValue(pSQLCommand)
Else
If pConnectionId > 0 Then
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
Return _DatabaseECM.GetScalarValueWithConnection(pSQLCommand, oConnectionString)
Else
Return _DatabaseECM.GetScalarValue(pSQLCommand)
End If
End Select
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
@@ -455,21 +458,19 @@ Public Class DatabaseWithFallback
Private Function ExecuteNonQueryFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Boolean
Try
Select Case DatabaseType
Case Constants.DatabaseType.ECM
Return _DatabaseECM.ExecuteNonQuery(pSQLCommand)
Case Constants.DatabaseType.IDB
Return _DatabaseIDB.ExecuteNonQuery(pSQLCommand)
Case Else
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
If oConnectionString = String.Empty Then
Return _DatabaseECM.ExecuteNonQuery(pSQLCommand)
Else
If pConnectionId > 0 Then
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
Return _DatabaseECM.ExecuteNonQueryWithConnection(pSQLCommand, oConnectionString)
Else
Return _DatabaseECM.ExecuteNonQuery(pSQLCommand)
End If
End Select
Catch ex As Exception
_Logger.Error(ex)
Return False

View File

@@ -10,7 +10,8 @@
<AssemblyName>DigitalData.Modules.EDMI.API</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -44,8 +45,8 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@@ -101,6 +102,7 @@
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
@@ -306,14 +308,6 @@
<Project>{eaf0ea75-5fa7-485d-89c7-b2d843b03a96}</Project>
<Name>Database</Name>
</ProjectReference>
<ProjectReference Include="..\Filesystem\Filesystem.vbproj">
<Project>{991d0231-4623-496d-8bd0-9ca906029cbc}</Project>
<Name>Filesystem</Name>
</ProjectReference>
<ProjectReference Include="..\Language\Language.vbproj">
<Project>{d3c8cfed-d6f6-43a8-9bdf-454145d0352f}</Project>
<Name>Language</Name>
</ProjectReference>
<ProjectReference Include="..\Logging\Logging.vbproj">
<Project>{903b2d7d-3b80-4be9-8713-7447b704e1b0}</Project>
<Name>Logging</Name>

View File

@@ -1,16 +1,17 @@
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Logging
Public Class Helpers
Private ReadOnly LogConfig As LogConfig
Private ReadOnly Logger As Logger
Private ReadOnly FileEx As Filesystem.File
Private ReadOnly FileEx As FilesystemEx
Public Sub New(pLogConfig As LogConfig)
LogConfig = pLogConfig
Logger = pLogConfig.GetLogger()
FileEx = New Filesystem.File(pLogConfig)
FileEx = New FilesystemEx(pLogConfig)
End Sub
Public Function GetFileProperties(pFilePath As String, pDateImportedAt As Date) As FileProperties

View File

@@ -1,4 +1,5 @@
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Logging
Namespace Modules
@@ -6,14 +7,14 @@ Namespace Modules
Friend ReadOnly LogConfig As LogConfig
Friend ReadOnly Logger As Logger
Friend ReadOnly Channel As IEDMIServiceChannel
Friend ReadOnly FileEx As Filesystem.File
Friend ReadOnly FileEx As FilesystemEx
Friend ReadOnly Helpers As Helpers
Public Sub New(pLogConfig As LogConfig, pChannel As IEDMIServiceChannel)
LogConfig = pLogConfig
Logger = pLogConfig.GetLogger()
Channel = pChannel
FileEx = New Filesystem.File(pLogConfig)
FileEx = New FilesystemEx(pLogConfig)
Helpers = New Helpers(pLogConfig)
End Sub
End Class

View File

@@ -1,6 +1,5 @@
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Filesystem
Namespace Modules.IDB
Public Class NewFile

View File

@@ -12,8 +12,8 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("Digital Data")>
<Assembly: AssemblyProduct("EDMIAPI")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("1.5.4.0")>
<Assembly: AssemblyCopyright("Copyright © 2023")>
<Assembly: AssemblyTrademark("1.6.1.1")>
<Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.5.4.0")>
<Assembly: AssemblyFileVersion("1.5.4.0")>
<Assembly: AssemblyVersion("1.6.1.1")>
<Assembly: AssemblyFileVersion("1.6.1.1")>

View File

@@ -22,7 +22,7 @@ Namespace My.Resources
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0"), _
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
@@ -39,7 +39,7 @@ Namespace My.Resources
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
Get
If Object.ReferenceEquals(resourceMan, Nothing) Then
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("DigitalData.Modules.EDMIAPI.Resources", GetType(Resources).Assembly)
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("DigitalData.Modules.EDMI.API.Resources", GetType(Resources).Assembly)
resourceMan = temp
End If
Return resourceMan

View File

@@ -15,7 +15,7 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase
@@ -62,8 +62,8 @@ Namespace My
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
Friend Module MySettingsProperty
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")>
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
Friend ReadOnly Property Settings() As Global.DigitalData.Modules.EDMI.API.My.MySettings
Get
Return Global.DigitalData.Modules.EDMI.API.My.MySettings.Default

View File

@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.diagnostics>
<sources>
<!-- Dieser Abschnitt definiert die Protokollierungskonfiguration für My.Application.Log -->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="FileLog" />
<add name="FileLog"/>
<!-- Auskommentierung des nachfolgenden Abschnitts aufheben, um in das Anwendungsereignisprotokoll zu schreiben -->
<!--<add name="EventLog"/>-->
</listeners>
</source>
</sources>
<switches>
<add name="DefaultSwitch" value="Information" />
<add name="DefaultSwitch" value="Information"/>
</switches>
<sharedListeners>
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter" />
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/>
<!-- Auskommentierung des nachfolgenden Abschnitts aufheben und APPLICATION_NAME durch den Namen der Anwendung ersetzen, um in das Anwendungsereignisprotokoll zu schreiben -->
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
</sharedListeners>
@@ -25,7 +25,7 @@
<netTcpBinding>
<binding name="NetTcpBinding_IEDMIService" transferMode="Streamed">
<security>
<transport sslProtocols="None" />
<transport sslProtocols="None"/>
</security>
</binding>
</netTcpBinding>
@@ -33,7 +33,7 @@
<client>
<endpoint address="net.tcp://localhost:9000/DigitalData/Services/Main" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IEDMIService" contract="EDMIServiceReference.IEDMIService" name="NetTcpBinding_IEDMIService">
<identity>
<userPrincipalName value="Administrator@dd-san01.dd-gan.local.digitaldata.works" />
<userPrincipalName value="Administrator@dd-san01.dd-gan.local.digitaldata.works"/>
</identity>
</endpoint>
</client>
@@ -41,9 +41,9 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FirebirdSql.Data.FirebirdClient" publicKeyToken="3750abcc3150b00c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-7.5.0.0" newVersion="7.5.0.0" />
<assemblyIdentity name="FirebirdSql.Data.FirebirdClient" publicKeyToken="3750abcc3150b00c" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-7.5.0.0" newVersion="7.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="NLog" version="5.0.5" targetFramework="net461" />
</packages>

View File

@@ -10,8 +10,9 @@
<AssemblyName>DigitalData.Modules.Encryption</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -45,8 +46,8 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />

View File

@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("Encryption")>
<Assembly: AssemblyCopyright("Copyright © 2021")>
<Assembly: AssemblyTrademark("")>
<Assembly: AssemblyTrademark("1.2.0.0")>
<Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' indem Sie "*" wie unten gezeigt eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.1.0.0")>
<Assembly: AssemblyFileVersion("1.1.0.0")>
<Assembly: AssemblyVersion("1.2.0.0")>
<Assembly: AssemblyFileVersion("1.2.0.0")>

View File

@@ -22,7 +22,7 @@ Namespace My.Resources
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _

View File

@@ -15,7 +15,7 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="NLog" version="5.0.5" targetFramework="net461" />
</packages>

View File

@@ -1,18 +0,0 @@
Imports System.Runtime.Serialization
<Serializable>
Public Class DocumentObject
<DataMember(Name:="FileName")>
Public ReadOnly FileName As String
<DataMember(Name:="ContainerId")>
Public ReadOnly ContainerId As String
<DataMember(Name:="DocumentId")>
Public ReadOnly DocumentId As Int64
Public Sub New(ContainerId As String, DocumentId As Int64, FileName As String)
Me.ContainerId = ContainerId
Me.DocumentId = DocumentId
Me.FileName = FileName
End Sub
End Class

View File

@@ -1,193 +0,0 @@
Imports System.IO
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Encryption
Imports ProtoBuf
''' <module>FileContainer</module>
''' <version>0.0.0.2</version>
''' <date>21.11.2018</date>
''' <summary>
''' File Container for securely saving files
''' </summary>
''' <dependencies>
''' NLog, >= 4.5.8
''' </dependencies>
''' <params>
''' LogConfig, DigitalData.Module.Logging.LogConfig
''' A LogConfig object
''' Password, String
''' The Password to Encrypt
''' Path, String
''' The Path to save/load the container
''' </params>
''' <example>
''' dim oContainer = Container.Create(logConfig, "pass", "E:\some.container")
''' dim oContainer = Container.Load(logConfig, "pass", "E:\some.container")
'''
''' dim oContainer = new Container(logConfig, "pass", "E:\some.container")
''' oContainer.Save()
'''
''' dim oContainer = new Container(logConfig, "pass", "E:\some.container")
''' oContainer.Contents = oSomeData
''' oContainer.Save()
'''
''' dim oContainer = new Container(logConfig, "pass", "E:\some.container")
''' oContainer.Load()
''' dim oContents = oContainer.Contents
'''
''' dim oContainer = new Container(logConfig, "pass", "E:\some.container")
''' oContainer.Load()
''' oContainer.Contents = oSomeOtherData
''' oContainer.Save()
''' oContainer.SaveAs("E:\some2.container")
''' </example>
Public Class FileContainer
Private _crypto As Encryption.Encryption
Private _compression As Compression
Private _inner As FileContainerInner
Private _logger As Logger
Private _logConfig As LogConfig
Private _path As String
Public Property Contents As Byte()
Get
Return _inner.Contents
End Get
Set(value As Byte())
_inner.Contents = value
End Set
End Property
Public ReadOnly Property ContainerId As String
Get
Return _inner.FileId
End Get
End Property
Public ReadOnly Property CreatedAt As String
Get
Return _inner.CreatedAt
End Get
End Property
Public ReadOnly Property UpdatedAt As String
Get
Return _inner.UpdatedAt
End Get
End Property
Public Shared Function Create(LogConfig As LogConfig, Password As String) As FileContainer
Dim oContainer = New FileContainer(LogConfig, Password)
Return oContainer
End Function
Public Shared Function Load(LogConfig As LogConfig, Password As String, Path As String) As FileContainer
Dim oContainer = New FileContainer(LogConfig, Password, Path)
oContainer.Load()
Return oContainer
End Function
Public Sub New(LogConfig As LogConfig, Password As String)
_logger = LogConfig.GetLogger()
_crypto = New Encryption.Encryption(LogConfig, Password)
_compression = New Compression(LogConfig)
_inner = New FileContainerInner()
End Sub
Public Sub New(LogConfig As LogConfig, Password As String, Path As String)
MyClass.New(LogConfig, Password)
_path = Path
End Sub
Public Sub SetFile(Contents As Byte(), FileName As String)
_inner.Contents = Contents
_inner.UpdatedAt = Date.Now
_inner.FileName = FileName
End Sub
Public Function GetFile() As FileContainerInner
Return _inner
End Function
Public Sub Save()
If IsNothing(_path) Then
Throw New ArgumentException("Path not set")
End If
SaveAs(_path)
End Sub
Public Sub SaveAs(Path As String)
Try
WriteBytesToFile(TransformToBytes(_inner), Path)
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Sub
Public Sub Load()
If IsNothing(_path) Then
Throw New ArgumentException("Path not set")
End If
LoadFrom(_path)
End Sub
Public Sub LoadFrom(Path As String)
Try
_inner = TransformToObject(ReadBytesFromFile(_path))
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Sub
Private Function TransformToBytes([Object] As FileContainerInner) As Byte()
Dim oBytes = Serialize([Object])
Dim oCompressed = _compression.Compress(oBytes)
Dim oEncrypted = _crypto.Encrypt(oCompressed)
Return oEncrypted
End Function
Private Function TransformToObject(Bytes As Byte()) As FileContainerInner
Dim oDecrypted = _crypto.Decrypt(Bytes)
Dim oDecompressed = _compression.Decompress(oDecrypted)
Dim oObject = Deserialize(oDecompressed)
Return oObject
End Function
Private Function Serialize(InnerData As FileContainerInner) As Byte()
Dim oBinaryData As Byte()
Using oStream As New MemoryStream
Serializer.Serialize(oStream, InnerData)
oBinaryData = oStream.ToArray()
End Using
Return oBinaryData
End Function
Private Function Deserialize(InnerData As Byte()) As FileContainerInner
Dim oObject As FileContainerInner
Using oStream As New MemoryStream(InnerData)
oObject = Serializer.Deserialize(Of FileContainerInner)(oStream)
End Using
Return oObject
End Function
Private Sub WriteBytesToFile(Data As Byte(), FilePath As String)
Using oSourceStream As New FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
oSourceStream.Write(Data, 0, Data.Length)
oSourceStream.Flush()
End Using
End Sub
Private Function ReadBytesFromFile(FilePath As String) As Byte()
Using oFileStream = New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096)
Dim oBuffer As Byte() = New Byte(oFileStream.Length - 1) {}
oFileStream.Read(oBuffer, 0, oFileStream.Length)
oFileStream.Close()
Return oBuffer
End Using
End Function
End Class

View File

@@ -1,23 +0,0 @@
Imports ProtoBuf
<Serializable>
<ProtoContract>
Public Class FileContainerInner
<ProtoMember(1)>
Public FileId As String
<ProtoMember(2)>
Public Contents As Byte()
<ProtoMember(3)>
Public CreatedAt As DateTime
<ProtoMember(4)>
Public UpdatedAt As DateTime
<ProtoMember(5)>
Public FileName As String
Public Sub New()
FileId = Guid.NewGuid().ToString
CreatedAt = Date.Now
UpdatedAt = Date.Now
End Sub
End Class

View File

@@ -1,132 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{991D0231-4623-496D-8BD0-9CA906029CBC}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>DigitalData.Modules.Filesystem</RootNamespace>
<AssemblyName>DigitalData.Modules.Filesystem</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>DigitalData.Modules.Filesystem.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>DigitalData.Modules.Filesystem.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>Off</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="protobuf-net, Version=2.4.0.0, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
<HintPath>..\packages\protobuf-net.2.4.0\lib\net40\protobuf-net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Import Include="Microsoft.VisualBasic" />
<Import Include="System" />
<Import Include="System.Collections" />
<Import Include="System.Collections.Generic" />
<Import Include="System.Data" />
<Import Include="System.Diagnostics" />
<Import Include="System.Linq" />
<Import Include="System.Xml.Linq" />
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileContainer\DocumentObject.vb" />
<Compile Include="FileContainer\FileContainer.vb" />
<Compile Include="File.vb" />
<Compile Include="FileContainer\FileContainerInner.vb" />
<Compile Include="FileWatcher\FileWatcher.vb" />
<Compile Include="FileWatcher\FileWatcherFilters.vb" />
<Compile Include="FileWatcher\FileWatcherProperties.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="My Project\Settings.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
<CustomToolNamespace>My.Resources</CustomToolNamespace>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
<LastGenOutput>Application.Designer.vb</LastGenOutput>
</None>
<None Include="My Project\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<CustomToolNamespace>My</CustomToolNamespace>
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Encryption\Encryption.vbproj">
<Project>{8a8f20fc-c46e-41ac-bee7-218366cfff99}</Project>
<Name>Encryption</Name>
</ProjectReference>
<ProjectReference Include="..\Logging\Logging.vbproj">
<Project>{903b2d7d-3b80-4be9-8713-7447b704e1b0}</Project>
<Name>Logging</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>

View File

@@ -1,13 +0,0 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On

View File

@@ -1,35 +0,0 @@
Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices
' Allgemeine Informationen über eine Assembly werden über die folgenden
' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
' die einer Assembly zugeordnet sind.
' Werte der Assemblyattribute überprüfen
<Assembly: AssemblyTitle("Modules.Filesystem")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("Digital Data")>
<Assembly: AssemblyProduct("Modules.Filesystem")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("1.3.1.1")>
<Assembly: ComVisible(False)>
'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
<Assembly: Guid("2787495c-e65f-4730-be0c-af87bede4b11")>
' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
'
' Hauptversion
' Nebenversion
' Buildnummer
' Revision
'
' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.3.1.1")>
<Assembly: AssemblyFileVersion("1.3.1.1")>

View File

@@ -1,63 +0,0 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Imports System
Namespace My.Resources
'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
'-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
Friend Module Resources
Private resourceMan As Global.System.Resources.ResourceManager
Private resourceCulture As Global.System.Globalization.CultureInfo
'''<summary>
''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
Get
If Object.ReferenceEquals(resourceMan, Nothing) Then
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("DigitalData.Modules.Filesystem.Resources", GetType(Resources).Assembly)
resourceMan = temp
End If
Return resourceMan
End Get
End Property
'''<summary>
''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Property Culture() As Global.System.Globalization.CultureInfo
Get
Return resourceCulture
End Get
Set
resourceCulture = value
End Set
End Property
End Module
End Namespace

View File

@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1,73 +0,0 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
#Region "Automatische My.Settings-Speicherfunktion"
#If _MyType = "WindowsForms" Then
Private Shared addedHandler As Boolean
Private Shared addedHandlerLockObject As New Object
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
If My.Application.SaveMySettingsOnExit Then
My.Settings.Save()
End If
End Sub
#End If
#End Region
Public Shared ReadOnly Property [Default]() As MySettings
Get
#If _MyType = "WindowsForms" Then
If Not addedHandler Then
SyncLock addedHandlerLockObject
If Not addedHandler Then
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
addedHandler = True
End If
End SyncLock
End If
#End If
Return defaultInstance
End Get
End Property
End Class
End Namespace
Namespace My
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
Friend Module MySettingsProperty
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
Friend ReadOnly Property Settings() As Global.DigitalData.Modules.Filesystem.My.MySettings
Get
Return Global.DigitalData.Modules.Filesystem.My.MySettings.Default
End Get
End Property
End Module
End Namespace

View File

@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="protobuf-net" version="2.4.0" targetFramework="net461" />
</packages>

View File

@@ -193,6 +193,8 @@ Public Class ActiveDirectoryInterface
.FirebirdSyskey = oMap.FirebirdSyskey,
.MSSQLColumn = oMap.MSSQLColumn
})
Else
_logger.Debug("Attribute [{0}] is empty.", oMap.AttributeName)
End If
Next
Else

View File

@@ -8,6 +8,7 @@ Public Class ADUser
Public Property GivenName As String
Public Property Middlename As String
Public Property Email As String
Public Property Language As String
Public CustomAttributes As List(Of CustomAttribute)

View File

@@ -1,6 +1,6 @@
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports DigitalData.Modules.Base
Namespace SyncUsers
Public Class SyncUsersMSSQL
@@ -42,7 +42,7 @@ Namespace SyncUsers
End Try
For Each oUser In Users
Dim oUserId As Int64
Dim oUserId As Long
Dim oUserExists As Boolean
' Check if user already exists
@@ -68,7 +68,7 @@ Namespace SyncUsers
_logger.Debug("Creating new user for [{0}]", oUser)
oUserId = CreateUser(oUser)
_logger.Debug("User created with Id [{0}]", oUserId)
_logger.Info("Added new User [{0}]", oUser.samAccountName)
_logger.Info("Added new User [{0}]", oUser)
oCreatedUsers.Add(oUser)
Else
@@ -76,7 +76,7 @@ Namespace SyncUsers
oUserId = UpdateUser(oUser)
If oUserId <> 0 Then
_logger.Debug("User created with Id [{0}]", oUserId)
_logger.Info("Updated User [{0}]", oUser.samAccountName)
_logger.Info("Updated User [{0}]", oUser)
oUpdatedUsers.Add(oUser)
End If
@@ -84,7 +84,7 @@ Namespace SyncUsers
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could Not create/update user [{0}]. Skipping.", oUser.samAccountName)
_logger.Warn("Could Not create/update user [{0}]. Skipping.", oUser)
Continue For
End Try
@@ -99,7 +99,7 @@ Namespace SyncUsers
' Add the user to group
Try
If AddUserToGroup(oUserId, oGroupId) Then
_logger.Info("User [{0}] added to group [{1}]", oUser.samAccountName, GroupName)
_logger.Info("User [{0}] added to group [{1}]", oUser, GroupName)
End If
Catch ex As Exception
_logger.Error(ex)
@@ -175,7 +175,8 @@ Namespace SyncUsers
Dim oSQL As String = $"SELECT GUID FROM TBDD_USER WHERE UPPER(USERNAME) = UPPER('{UserName}')"
Dim oUserId = _mssql.GetScalarValue(oSQL)
If IsDBNull(oUserId) OrElse oUserId = 0 Then
If IsDBNull(oUserId) OrElse IsNothing(oUserId) OrElse oUserId = 0 Then
_logger.Debug("User [{0}] does not exist", UserName)
Return 0
End If
@@ -194,9 +195,15 @@ Namespace SyncUsers
End If
Dim oUserId As Integer = GetUserId(User.samAccountName)
_logger.Debug("UserId of User [{0}] is [{1}]", User, oUserId)
If oUserId = 0 Then
Dim oSQL As String = $"INSERT INTO TBDD_USER (PRENAME, NAME, USERNAME, EMAIL, ADDED_WHO) VALUES ('{User?.GivenName}', '{User?.Surname?.Replace("'", "''")}', UPPER('{User?.samAccountName?.Replace("'", "''")}'), '{User?.Email?.Replace("'", "''")}', '{ADDED_WHO}')"
Dim oPrename = User.GivenName.EscapeForSQL()
Dim oSurname = User.Surname.EscapeForSQL()
Dim oUsername = User.samAccountName.EscapeForSQL()
Dim oEmail = User.Email.EscapeForSQL()
Dim oSQL As String = $"INSERT INTO TBDD_USER (PRENAME, NAME, USERNAME, EMAIL, ADDED_WHO) VALUES ('{oPrename}', '{oSurname}', UPPER('{oUsername}'), '{oEmail}', '{ADDED_WHO}')"
Dim oResult = _mssql.ExecuteNonQuery(oSQL)
If oResult = True Then
@@ -230,11 +237,11 @@ Namespace SyncUsers
Dim oUserId As Integer = GetUserId(User.samAccountName)
If Not IsNothing(oUserId) Then
If oUserId > 0 Then
Dim oGivenName As String = EscapeQuotes(User.GivenName)
Dim oSurname As String = EscapeQuotes(User.Surname)
Dim oEmail As String = EscapeQuotes(User.Email)
Dim oPrename = User.GivenName.EscapeForSQL()
Dim oSurname = User.Surname.EscapeForSQL()
Dim oEmail = User.Email.EscapeForSQL()
Dim oSQL As String = $"UPDATE TBDD_USER SET PRENAME = '{oGivenName}', NAME = '{oSurname}', EMAIL = '{oEmail}', CHANGED_WHO = '{ADDED_WHO}' WHERE GUID = {oUserId}"
Dim oSQL As String = $"UPDATE TBDD_USER SET PRENAME = '{oPrename}', NAME = '{oSurname}', EMAIL = '{oEmail}', CHANGED_WHO = '{ADDED_WHO}' WHERE GUID = {oUserId}"
Dim oResult = _mssql.ExecuteNonQuery(oSQL)
If oResult = True Then
@@ -256,11 +263,6 @@ Namespace SyncUsers
End Try
End Function
Private Function EscapeQuotes(pString As String)
Dim oString = Utils.NotNull(pString, String.Empty)
Return oString.Replace("'", "''")
End Function
Public Sub AddCustomAttributesToUser(User As ADUser, UserId As Integer) Implements ISyncUsers.AddCustomAttributesToUser
Dim oCustomAttributes = User.CustomAttributes

View File

@@ -51,8 +51,8 @@
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.5\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@@ -111,6 +111,8 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="ZUGFeRDInterface\PDFConverter.vb" />
<Compile Include="ZUGFeRDInterface\Validator.vb" />
<Compile Include="ZUGFeRDInterface\Version1.0\CrossIndustryDocumentType.vb" />
<Compile Include="ZUGFeRDInterface.vb" />
<Compile Include="ZUGFeRDInterface\FileGroups.vb" />
@@ -154,14 +156,14 @@
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Base\Base.vbproj">
<Project>{6ea0c51f-c2b1-4462-8198-3de0b32b74f8}</Project>
<Name>Base</Name>
</ProjectReference>
<ProjectReference Include="..\Database\Database.vbproj">
<Project>{eaf0ea75-5fa7-485d-89c7-b2d843b03a96}</Project>
<Name>Database</Name>
</ProjectReference>
<ProjectReference Include="..\Language\Language.vbproj">
<Project>{d3c8cfed-d6f6-43a8-9bdf-454145d0352f}</Project>
<Name>Language</Name>
</ProjectReference>
<ProjectReference Include="..\Logging\Logging.vbproj">
<Project>{903b2d7d-3b80-4be9-8713-7447b704e1b0}</Project>
<Name>Logging</Name>

View File

@@ -12,8 +12,8 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("Digital Data")>
<Assembly: AssemblyProduct("Modules.Interfaces")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("1.7.4.0")>
<Assembly: AssemblyCopyright("Copyright © 2023")>
<Assembly: AssemblyTrademark("1.12.0.0")>
<Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.7.4.0")>
<Assembly: AssemblyFileVersion("1.7.4.0")>
<Assembly: AssemblyVersion("1.12.0.0")>
<Assembly: AssemblyFileVersion("1.12.0.0")>

View File

@@ -15,7 +15,7 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase

View File

@@ -1,56 +1,150 @@
Imports System.IO
Imports System.Collections.Generic
Imports System.IO
Imports System.Reflection.Emit
Imports System.Xml
Imports System.Xml.Serialization
Imports System.Xml.XPath
Imports System.Xml.Xsl
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Interfaces.ZUGFeRD
Imports DigitalData.Modules.Interfaces.ZUGFeRDInterface
Imports DigitalData.Modules.Logging
Imports GdPicture14
Public Class ZUGFeRDInterface
Private _logConfig As LogConfig
Private _logger As Logger
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Private ReadOnly _Options As ZugferdOptions
Private ReadOnly _Validator As Validator
' These constants define the specification markers for the different
' zugferd document schema versions. These markers need to be used to
' define the property map in the database (column SPECIFICATION).
Public Const ZUGFERD_SPEC_DEFAULT = "DEFAULT"
Public Const ZUGFERD_SPEC_10 = "ZUGFERD_10"
Public Const ZUGFERD_SPEC_2x = "ZUGFERD_2x"
Private ReadOnly ValidFilenames As New List(Of String) From {
PDFEmbeds.ZUGFERD_XML_FILENAME.ToUpper,
PDFEmbeds.FACTUR_X_XML_FILENAME_DE.ToUpper,
PDFEmbeds.FACTUR_X_XML_FILENAME_FR.ToUpper
}
Private AllowedFilenames As New List(Of String)
Public Enum ErrorType
NoValidFile
NoZugferd
NoValidZugferd
MissingProperties
UnsupportedFormat
FileTooBig
UnknownError
End Enum
Public ReadOnly Property FileGroup As FileGroups
Public ReadOnly Property PropertyValues As PropertyValues
Public Sub New(LogConfig As LogConfig, GDPictureKey As String)
_logConfig = LogConfig
Public Class ZugferdOptions
Public Property AllowFacturX_Filename As Boolean = True
Public Property AllowXRechnung_Filename As Boolean = True
Public Property AllowZugferd_1_0_Schema As Boolean = True
Public Property AllowZugferd_2_x_Schema As Boolean = True
End Class
Public Class ZugferdResult
Public Property DataFileName As String
Public Property XElementObject As XElement
Public Property SchemaObject As Object
Public Property Specification As String
Public Property ValidationErrors As New List(Of ZugferdValidationError)
End Class
Public Class ZugferdValidationError
Public ElementName As String
Public ElementValue As String
Public ErrorMessage As String
End Class
''' <summary>
''' Create a new instance of ZUGFeRDInterface
''' </summary>
''' <param name="pLogConfig">A LogConfig object</param>
''' <param name="pGDPictureKey">A valid GDPicture License</param>
''' <param name="pOptions">Optional parameters to control various settings</param>
Public Sub New(pLogConfig As LogConfig, pGDPictureKey As String, Optional pOptions As ZugferdOptions = Nothing)
_logConfig = pLogConfig
_logger = _logConfig.GetLogger()
_Validator = New Validator(_logConfig)
If pOptions Is Nothing Then
_Options = New ZugferdOptions()
Else
_Options = pOptions
End If
ApplyFilenameOptions(_Options)
FileGroup = New FileGroups(_logConfig)
PropertyValues = New PropertyValues(_logConfig)
Try
Dim oLicenseManager As New LicenseManager
oLicenseManager.RegisterKEY(GDPictureKey)
oLicenseManager.RegisterKEY(pGDPictureKey)
Catch ex As Exception
_logger.Warn("GDPicture License could not be registered!")
_logger.Error(ex)
End Try
End Sub
Private Sub ApplyFilenameOptions(pOptions As ZugferdOptions)
Dim oAllowedFilenames As List(Of String) = ValidFilenames
If pOptions.AllowFacturX_Filename = False Then
oAllowedFilenames = oAllowedFilenames.
Except(New List(Of String) From {PDFEmbeds.FACTUR_X_XML_FILENAME_FR}).ToList()
End If
If pOptions.AllowXRechnung_Filename = False Then
oAllowedFilenames = oAllowedFilenames.
Except(New List(Of String) From {PDFEmbeds.FACTUR_X_XML_FILENAME_DE}).ToList()
End If
AllowedFilenames = oAllowedFilenames
End Sub
Public Function FilterPropertyMap(pPropertyMap As Dictionary(Of String, XmlItemProperty), pSpecification As String) As Dictionary(Of String, XmlItemProperty)
_logger.Debug("Filtering Property map for Specification [{0}]", pSpecification)
If pSpecification = ZUGFERD_SPEC_10 Then
_logger.Debug("Special Case [{0}], including [{1}]", ZUGFERD_SPEC_10, ZUGFERD_SPEC_DEFAULT)
Return pPropertyMap.
Where(Function(kv) kv.Value.Specification = pSpecification Or kv.Value.Specification = ZUGFERD_SPEC_DEFAULT).
ToDictionary(Function(kv) kv.Key, Function(kv) kv.Value)
Else
_logger.Debug("Using Specification [{0}]", pSpecification)
Return pPropertyMap.
Where(Function(kv) kv.Value.Specification = pSpecification).
ToDictionary(Function(kv) kv.Key, Function(kv) kv.Value)
End If
End Function
''' <summary>
''' Validates a ZUGFeRD File and extracts the XML Document from it
''' </summary>
''' <param name="Path"></param>
''' <exception cref="ZUGFeRDExecption"></exception>
''' <returns></returns>
Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As Object
Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Path)
Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As ZugferdResult
Dim oResult = ValidateZUGFeRDFileWithGDPicture(Path)
oResult = ValidateZUGFeRDDocument(oResult)
If IsNothing(oXmlDocument) Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
If oResult.ValidationErrors.Any() Then
Throw New ValidationException() With {
.ValidationErrors = oResult.ValidationErrors
}
End If
Return SerializeZUGFeRDDocument(oXmlDocument)
Return SerializeZUGFeRDDocument(oResult)
End Function
''' <summary>
@@ -58,29 +152,36 @@ Public Class ZUGFeRDInterface
''' </summary>
''' <param name="Stream"></param>
''' <exception cref="ZUGFeRDExecption"></exception>
''' <returns></returns>
Public Function ExtractZUGFeRDFileWithGDPicture(Stream As Stream) As Object
Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Stream)
Public Function ExtractZUGFeRDFileWithGDPicture(Stream As Stream) As ZugferdResult
Dim oResult = ValidateZUGFeRDFileWithGDPicture(Stream)
oResult = ValidateZUGFeRDDocument(oResult)
If IsNothing(oXmlDocument) Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
If oResult.ValidationErrors.Any() Then
_logger.Info("Validation found [{0}] errors", oResult.ValidationErrors.Count)
oResult.ValidationErrors.ForEach(
Sub(e) _logger.Info("Field [{0}] with value [{1}] has error: [{2}]", e.ElementName, e.ElementValue, e.ErrorMessage)
)
Throw New ValidationException() With {
.ValidationErrors = oResult.ValidationErrors
}
End If
Return SerializeZUGFeRDDocument(oXmlDocument)
Return SerializeZUGFeRDDocument(oResult)
End Function
''' <summary>
''' Validates a ZUGFeRD File and extracts the XML Document from it
''' </summary>
''' <param name="Stream"></param>
''' <param name="pStream"></param>
''' <exception cref="ZUGFeRDExecption"></exception>
''' <returns></returns>
Public Function ValidateZUGFeRDFileWithGDPicture(Stream As Stream) As XPathDocument
''' <returns>The embedded xml data as an XPath document</returns>
Public Function ValidateZUGFeRDFileWithGDPicture(pStream As Stream) As ZugferdResult
Dim oEmbedExtractor = New PDFEmbeds(_logConfig)
Dim oAllowedExtensions = New List(Of String) From {"xml"}
Try
Dim oFiles = oEmbedExtractor.Extract(Stream, oAllowedExtensions)
' Extract XML attachments only!
Dim oFiles = oEmbedExtractor.Extract(pStream, New List(Of String) From {"xml"})
' Attachments are in this case the files that are embedded into a pdf file,
' like for example the zugferd-invoice.xml file
@@ -92,17 +193,24 @@ Public Class ZUGFeRDInterface
Throw ex
Catch ex As Exception
_logger.Warn("Error while validating ZUGFeRD file with GDPicture")
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function ValidateZUGFeRDFileWithGDPicture(Path As String) As XPathDocument
''' <summary>
''' Validates a ZUGFeRD File and extracts the XML Document from it
''' </summary>
''' <param name="pPath"></param>
''' <exception cref="ZUGFeRDExecption"></exception>
''' <returns>The embedded xml data as an XPath document</returns>
Public Function ValidateZUGFeRDFileWithGDPicture(pPath As String) As ZugferdResult
Dim oEmbedExtractor = New PDFEmbeds(_logConfig)
Dim oAllowedExtensions = New List(Of String) From {"xml"}
Try
Dim oFiles = oEmbedExtractor.Extract(Path, oAllowedExtensions)
' Extract XML attachments only!
Dim oFiles = oEmbedExtractor.Extract(pPath, New List(Of String) From {"xml"})
' Attachments are in this case the files that are embedded into a pdf file,
' like for example the zugferd-invoice.xml file
@@ -114,43 +222,48 @@ Public Class ZUGFeRDInterface
Throw ex
Catch ex As Exception
_logger.Warn("Error while validating ZUGFeRD file with GDPicture")
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function HandleEmbeddedFiles(Results As List(Of PDFEmbeds.EmbeddedFile)) As XPathDocument
Dim oXmlDocument As XPathDocument
If Results Is Nothing Then
Private Function HandleEmbeddedFiles(pResults As List(Of PDFEmbeds.EmbeddedFile)) As ZugferdResult
If pResults Is Nothing Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil die Attachments nicht gelesen werden konnten.")
End If
If Results.Count = 0 Then
If pResults.Count = 0 Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil sie keine Attachments enthält.")
End If
Dim oValidFilenames As New List(Of String) From {
PDFEmbeds.ZUGFERD_XML_FILENAME.ToUpper,
PDFEmbeds.FACTUR_X_XML_FILENAME_DE.ToUpper,
PDFEmbeds.FACTUR_X_XML_FILENAME_FR.ToUpper
}
' Find the first file which filename matches the valid filenames for embedded invoice files
Dim oFoundResult As PDFEmbeds.EmbeddedFile = Results.
Where(Function(result) oValidFilenames.Contains(result.FileName.ToUpper)).
Dim oValidResult As PDFEmbeds.EmbeddedFile = pResults.
Where(Function(f) ValidFilenames.Contains(f.FileName.ToUpper)).
FirstOrDefault()
If oFoundResult Is Nothing Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil die zugferd-invoice.xml nicht gefunden wurde.")
If oValidResult Is Nothing Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil keine entsprechende XML-Datei gefunden wurde.")
End If
' Search the embedded files for the ones which are allowed as per the configuration.
' The config might say, allow ZUGFeRD but not Factur-X.
Dim oAllowedResult As PDFEmbeds.EmbeddedFile = pResults.
Where(Function(f) AllowedFilenames.Contains(f.FileName.ToUpper)).
FirstOrDefault()
If oAllowedResult Is Nothing Then
Throw New ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Datei ist eine ZUGFeRD Datei, aber das Format wird nicht unterstützt.", oAllowedResult.FileName)
End If
Try
Using oStream As New MemoryStream(oFoundResult.FileContents)
oXmlDocument = New XPathDocument(oStream)
Using oStream As New MemoryStream(oAllowedResult.FileContents)
Return New ZugferdResult With {
.DataFileName = oAllowedResult.FileName,
.XElementObject = XElement.Load(oStream)
}
End Using
Return oXmlDocument
Catch ex As ZUGFeRDExecption
' Don't log ZUGFeRD Exceptions here, they should be handled by the calling code.
' It also produces misleading error messages when checking if an attachment is a zugferd file.
@@ -162,46 +275,87 @@ Public Class ZUGFeRDInterface
End Try
End Function
Public Function SerializeZUGFeRDDocument(Document As XPathDocument) As Object
Private Class AllowedType
Public SchemaType As Type
Public Specification As String
End Class
Public Function ValidateZUGFeRDDocument(pResult As ZugferdResult) As ZugferdResult
Return _Validator.ValidateZUGFeRDDocument(pResult)
End Function
Public Function SerializeZUGFeRDDocument(pResult As ZugferdResult) As ZugferdResult
Try
Dim oNavigator As XPathNavigator = Document.CreateNavigator()
Dim oReader As XmlReader
Dim oResult = Nothing
Dim oTypes As New List(Of Type) From {
GetType(ZUGFeRD.Version1_0.CrossIndustryDocumentType),
GetType(ZUGFeRD.Version2_0.CrossIndustryInvoiceType),
GetType(ZUGFeRD.Version2_1_1.CrossIndustryInvoiceType),
GetType(ZUGFeRD.Version2_2_FacturX.CrossIndustryInvoiceType)
}
Dim oObject As Object = Nothing
Dim oSpecification As String = Nothing
For Each oType In oTypes
_logger.Debug("Trying Type [{0}]", oType.FullName)
Dim oSerializer As New XmlSerializer(oType)
Dim oAllowedTypes As New List(Of AllowedType)
If _Options.AllowZugferd_1_0_Schema Then
oAllowedTypes.Add(New AllowedType With {
.SchemaType = GetType(Version1_0.CrossIndustryDocumentType),
.Specification = ZUGFERD_SPEC_10
})
End If
If _Options.AllowZugferd_2_x_Schema Then
oAllowedTypes.AddRange(New List(Of AllowedType) From {
New AllowedType With {
.SchemaType = GetType(Version2_0.CrossIndustryInvoiceType),
.Specification = ZUGFERD_SPEC_2x
},
New AllowedType With {
.SchemaType = GetType(Version2_1_1.CrossIndustryInvoiceType),
.Specification = ZUGFERD_SPEC_2x
},
New AllowedType With {
.SchemaType = GetType(Version2_2_FacturX.CrossIndustryInvoiceType),
.Specification = ZUGFERD_SPEC_2x
}
})
End If
For Each oType In oAllowedTypes
Dim oTypeName As String = oType.SchemaType.FullName
Dim oSerializer As New XmlSerializer(oType.SchemaType)
_logger.Debug("Trying Type [{0}]", oTypeName)
Try
oReader = oNavigator.ReadSubtree()
oResult = oSerializer.Deserialize(oReader)
_logger.Debug("Serializing with type [{0}] succeeded", oType.FullName)
oReader = pResult.XElementObject.CreateReader()
oObject = oSerializer.Deserialize(oReader)
oSpecification = oType.Specification
_logger.Debug("Serializing with type [{0}] succeeded", oTypeName)
Exit For
Catch ex As Exception
_logger.Debug("Serializing with type [{0}] failed", oType.FullName)
_logger.Debug("Serializing with type [{0}] failed", oTypeName)
_logger.Debug(ex.Message)
_logger.Error(ex.InnerException?.Message)
If IsNothing(ex.InnerException) = False Then
_logger.Debug(ex.InnerException.Message)
End If
End Try
Next
If oResult Is Nothing Then
Throw New ApplicationException("No Types matched the given document. Document could not be serialized.")
If oObject Is Nothing Then
'Throw New ApplicationException("No Types matched the given document. Document could not be serialized.")
Throw New ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Unsupported Format")
End If
Return oResult
pResult.Specification = oSpecification
pResult.SchemaObject = oObject
Return pResult
Catch ex As ZUGFeRDExecption
_logger.Error(ex)
Throw ex
Catch ex As Exception
_logger.Error(ex)
Throw New ZUGFeRDExecption(ErrorType.NoValidZugferd, "Datei ist eine ungültige ZUGFeRD Datei.")
Dim oMessage = "Datei ist eine ungültige ZUGFeRD Datei oder das Format wird nicht unterstüzt, oder das Format ist deaktiviert."
Throw New ZUGFeRDExecption(ErrorType.NoValidZugferd, oMessage)
End Try
End Function
End Class

View File

@@ -1,13 +1,38 @@
Public Class Exceptions
Imports DigitalData.Modules.Interfaces.ZUGFeRDInterface
Public Class Exceptions
Public Class ZUGFeRDExecption
Inherits ApplicationException
Public ReadOnly Property ErrorType() As ZUGFeRDInterface.ErrorType
''' <summary>
''' Contains the name of the extracted xml file if already extracted.
''' </summary>
''' <returns>A filename like zugferd-invoice.xml</returns>
Public ReadOnly Property XmlFile As String = String.Empty
Public Sub New(ErrorType As ZUGFeRDInterface.ErrorType, Message As String)
MyBase.New(Message)
_ErrorType = ErrorType
End Sub
Public Sub New(ErrorType As ZUGFeRDInterface.ErrorType, Message As String, pXmlFileName As String)
MyBase.New(Message)
_ErrorType = ErrorType
_XmlFile = pXmlFileName
End Sub
End Class
Public Class ValidationException
Inherits ApplicationException
Public ValidationErrors As List(Of ZugferdValidationError)
Public Sub New()
MyBase.New("ZUGFeRD document found but validation failed!")
End Sub
End Class
End Class

View File

@@ -3,7 +3,7 @@ Imports System.Text.RegularExpressions
Imports DigitalData.Modules.Logging
Public Class FileGroups
Private _logger As Logger
Private ReadOnly _logger As Logger
Public Sub New(LogConfig As LogConfig)
_logger = LogConfig.GetLogger()
@@ -25,7 +25,7 @@ Public Class FileGroups
Dim oMessageId = GetMessageIdFromFileName(oFile.Name)
If oMessageId Is Nothing Then
_logger.Warn("File {0} did not have the required filename-format!", oMessageId)
_logger.Warn("File {0} did not have the required filename-format!", oFile.Name)
Continue For
End If
@@ -69,7 +69,9 @@ Public Class FileGroups
Private Function GetMessageIdFromFileName(Filename As String) As String
' Regex to find MessageId
' See also: https://stackoverflow.com/questions/3968500/regex-to-validate-a-message-id-as-per-rfc2822
Dim oRegex = "(((([a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*)|(""(([\x01-\x08\x0B\x0C\x0E-\x1F\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(\\[\x01-\x09\x0B\x0C\x0E-\x7F]))*""))@(([a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*)|(\[(([\x01-\x08\x0B\x0C\x0E-\x1F\x7F]|[\x21-\x5A\x5E-\x7E])|(\\[\x01-\x09\x0B\x0C\x0E-\x7F]))*\]))))~.+"
'Dim oRegex = "(((([a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*)|(""(([\x01-\x08\x0B\x0C\x0E-\x1F\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(\\[\x01-\x09\x0B\x0C\x0E-\x7F]))*""))@(([a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*)|(\[(([\x01-\x08\x0B\x0C\x0E-\x1F\x7F]|[\x21-\x5A\x5E-\x7E])|(\\[\x01-\x09\x0B\x0C\x0E-\x7F]))*\]))))~.+"
Dim oRegex = "([A-Z0-9]+)~ATTM\d+\..*"
Dim oMatch = Regex.Match(Filename, oRegex, RegexOptions.IgnoreCase)
If oMatch.Success Then

View File

@@ -0,0 +1,68 @@
Imports System.IO
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Logging
Imports GdPicture14
Public Class PDFConverter
Private ReadOnly _LogConfig As LogConfig
Private ReadOnly _Logger As Logger
Public Sub New(pLogConfig As LogConfig)
_LogConfig = pLogConfig
_Logger = pLogConfig.GetLogger()
End Sub
Public Function ConvertPDFADocumentToPDFDocument(pFilePath As String, pNewFilePath As String) As Boolean
Try
Using oGdPicturePDF As New GdPicturePDF()
Using oGdPicturePDFDestination As New GdPicturePDF()
' Load the source file into memory
If oGdPicturePDF.LoadFromFile(pFilePath, True) <> GdPictureStatus.OK Then
Throw New ApplicationException("File could not be loaded!")
End If
' Create a new pdf file
If oGdPicturePDFDestination.NewPDF() <> GdPictureStatus.OK Then
Throw New ApplicationException("New Pdf could not be created!")
End If
' Copy all pages from the source into the new pdf
If oGdPicturePDFDestination.ClonePages(oGdPicturePDF, "*") <> GdPictureStatus.OK Then
Throw New ApplicationException("Document could not be copied into new pdf!")
End If
' Close the source document
If oGdPicturePDF.CloseDocument() <> GdPictureStatus.OK Then
Throw New ApplicationException("Source document could not be closed!")
End If
' Set the file path
Dim oFinalFilePath = pFilePath
If Not String.IsNullOrWhiteSpace(pNewFilePath) Then
oFinalFilePath = pNewFilePath
End If
' Save the file to disk
If oGdPicturePDFDestination.SaveToFile(oFinalFilePath) <> GdPictureStatus.OK Then
Throw New ApplicationException("New document could not be saved to disk!")
End If
If oGdPicturePDFDestination.CloseDocument() <> GdPictureStatus.OK Then
Throw New ApplicationException("Destination document could not be closed!")
End If
End Using
End Using
Return True
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
End Function
End Class

View File

@@ -1,5 +1,7 @@
Imports System.Collections.Generic
Imports System.IO
Imports System.Reflection
Imports System.Runtime.Remoting.Messaging
Imports DigitalData.Modules.Logging
Imports GdPicture14
@@ -28,7 +30,7 @@ Public Class PDFEmbeds
Public Function Extract(FilePath As String, AllowedExtensions As List(Of String)) As List(Of EmbeddedFile)
Dim oFile As New List(Of EmbeddedFile)
Dim oFileInfo As FileInfo
Dim oExtensions = AllowedExtensions.ConvertAll(New Converter(Of String, String)(Function(ext) ext.ToUpper))
Dim oExtensions = AllowedExtensions.Select(Function(ext) ext.ToUpper).ToList()
Logger.Debug("Extracting embedded files from [{0}]", FilePath)
@@ -69,7 +71,7 @@ Public Class PDFEmbeds
''' <param name="AllowedExtensions">List of allowed extensions to be extracted</param>
Public Function Extract(Stream As Stream, AllowedExtensions As List(Of String)) As List(Of EmbeddedFile)
Dim oResults As New List(Of EmbeddedFile)
Dim oExtensions = AllowedExtensions.ConvertAll(New Converter(Of String, String)(Function(ext) ext.ToUpper))
Dim oExtensions = AllowedExtensions.Select(Function(ext) ext.ToUpper).ToList()
Logger.Debug("Extracting embedded files from stream")
@@ -91,6 +93,64 @@ Public Class PDFEmbeds
End Try
End Function
Public Function RemoveEmbeddedFiles(pFilePath As String) As Boolean
Dim oFile As New List(Of EmbeddedFile)
Dim oFileInfo As FileInfo
Logger.Debug("Removing embedded files from [{0}]", pFilePath)
Try
oFileInfo = New FileInfo(pFilePath)
Logger.Debug("Filename: {0}", oFileInfo.Name)
Logger.Debug("Filesize: {0} bytes", oFileInfo.Length)
Logger.Debug("Exists: {0}", oFileInfo.Exists)
Catch ex As Exception
Logger.Warn("File information for [{0}] could not be read!", pFilePath)
Logger.Error(ex)
End Try
Try
Using oGDPicturePDF As New GdPicturePDF()
If oGDPicturePDF.LoadFromFile(pFilePath, False) <> GdPictureStatus.OK Then
Dim oMessage = String.Format("The file [{0}] can't be loaded. Status: [{1}]", pFilePath, oGDPicturePDF.GetStat().ToString())
Throw New ApplicationException(oMessage)
End If
If DoRemove(oGDPicturePDF) = False Then
Dim oMessage = String.Format("Attachments for file [{0}] can't be removed. Status: [{1}]", pFilePath, oGDPicturePDF.GetStat().ToString())
Throw New ApplicationException(oMessage)
End If
End Using
Return True
Catch ex As Exception
Logger.Warn("Unexpected Error while Extracting attachments from File [{0}]", pFilePath)
Logger.Error(ex)
Return False
End Try
End Function
Private Function DoRemove(GDPicturePDF As GdPicturePDF) As Boolean
Dim oStatus As GdPictureStatus
Dim oEmbeddedFileCount As Integer = GDPicturePDF.GetEmbeddedFileCount()
If oStatus <> GdPictureStatus.OK Then
Logger.Warn("Embedded files could not be removed. Status: [{0}]", oStatus.ToString)
Return False
End If
If oEmbeddedFileCount = 0 Then
Return True
End If
While GDPicturePDF.GetEmbeddedFileCount() > 0
GDPicturePDF.DeleteEmbeddedFile(0)
End While
End Function
Private Function DoExtract(GDPicturePDF As GdPicturePDF, pExtensions As List(Of String)) As List(Of EmbeddedFile)
Dim oResults As New List(Of EmbeddedFile)
Dim oEmbeddedFileCount As Integer = GDPicturePDF.GetEmbeddedFileCount()
@@ -105,7 +165,17 @@ Public Class PDFEmbeds
If GDPicturePDF.GetStat() = GdPictureStatus.OK Then
Logger.Debug("Extracting embedded file [{0}]", oFileName)
Dim oExtension = New FileInfo(oFileName).Extension.ToUpper.Substring(1)
Dim oFileInfo = New FileInfo(oFileName)
Dim oExtension As String = oFileInfo.Extension
If String.IsNullOrWhiteSpace(oExtension) Then
Logger.Error("The embedded file [{0}] does not have any extension. Skipping.", oFileName)
Continue For
Else
' Jetzt wissen wir, das es eine Extension gibt!
oExtension = oFileInfo.Extension.ToUpper.Substring(1)
End If
If pExtensions.Contains(oExtension) Then
Dim oFileSize As Integer = GDPicturePDF.GetEmbeddedFileSize(oIndex)

View File

@@ -24,7 +24,7 @@ Public Class PropertyValues
Public TableName As String
Public TableColumn As String
Public ISRequired As Boolean
Public IsRequired As Boolean
Public GroupCounter As Integer = -1
Public Description As String
@@ -99,9 +99,7 @@ Public Class PropertyValues
Dim oIsRequired As Boolean = oColumn.Key.IsRequired
Dim oPropertyDescription As String = oColumn.Key.Description
Dim oRowCounter = oRowIndex + oGlobalGroupCounter + 1
If IsNothing(oRowCounter) Then
End If
' Returns nothing if oColumn.Value contains an empty list
Dim oPropertyValue = oColumn.Value.ElementAtOrDefault(oRowIndex)
@@ -127,7 +125,7 @@ Public Class PropertyValues
.GroupCounter = oRowCounter,
.TableName = oTableName,
.TableColumn = oTableColumn,
.ISRequired = oIsRequired
.IsRequired = oIsRequired
})
Next
Next
@@ -139,6 +137,7 @@ Public Class PropertyValues
For Each oItem As KeyValuePair(Of String, XmlItemProperty) In oDefaultProperties
Dim oPropertyValueList As List(Of Object)
Dim oTableColumn As String = oItem.Value.TableColumn
Dim oPropertyDescription As String = oItem.Value.Description
Dim oPropertyValue As Object = Nothing
Dim oTableName = oItem.Value.TableName
Dim oIsRequired = oItem.Value.IsRequired
@@ -146,7 +145,7 @@ Public Class PropertyValues
Try
oPropertyValueList = GetPropValue(Document, oItem.Key)
Catch ex As Exception
_logger.Warn("{2} # Unknown error occurred while fetching specification [{0}] in group [{1}]:", oTableColumn, oItem.Value.GroupScope, MessageId)
_logger.Warn("{2} # Unknown error occurred while fetching specification [{0}] in group [{1}]:", oPropertyDescription, oItem.Value.GroupScope, MessageId)
_logger.Error(ex)
oPropertyValueList = New List(Of Object)
End Try
@@ -164,24 +163,24 @@ Public Class PropertyValues
' This should hopefully show config errors
If TypeOf oPropertyValue Is List(Of Object) Then
_logger.Warn("Item with TableColumn [{0}] may be configured incorrectly", oTableColumn)
_logger.Warn("Item with specification [{0}] may be configured incorrectly", oPropertyDescription)
oPropertyValue = Nothing
End If
End Select
End If
Catch ex As Exception
_logger.Warn("Unknown error occurred while processing specification [{0}]:", oTableColumn)
_logger.Warn("Unknown error occurred while processing specification [{0}]:", oPropertyDescription)
_logger.Error(ex)
oPropertyValue = Nothing
End Try
If IsNothing(oPropertyValue) OrElse String.IsNullOrEmpty(oPropertyValue) Then
If oItem.Value.IsRequired Then
_logger.Warn("{0} # Specification [{1}] is empty, but marked as required! Skipping.", MessageId, oTableColumn)
oResult.MissingProperties.Add(oTableColumn)
_logger.Warn("{0} # Specification [{1}] is empty, but marked as required! Skipping.", MessageId, oPropertyDescription)
oResult.MissingProperties.Add(oPropertyDescription)
Continue For
Else
_logger.Debug("{0} # oPropertyValue for specification [{1}] is empty or not found. Skipping.", MessageId, oTableColumn)
_logger.Debug("{0} # oPropertyValue for specification [{1}] is empty or not found. Skipping.", MessageId, oPropertyDescription)
Continue For
End If
@@ -193,7 +192,7 @@ Public Class PropertyValues
.Value = oPropertyValue,
.TableName = oTableName,
.TableColumn = oTableColumn,
.ISRequired = oIsRequired
.IsRequired = oIsRequired
})
Next
@@ -240,6 +239,12 @@ Public Class PropertyValues
Obj = oInfo.GetValue(Obj, Nothing)
' TODO: This code should check for array properties by itself
' and should not rely on the user to
'If oInfo.PropertyType.IsArray Then
' Obj = Obj(0)
'End If
If oHasIndex Then
Obj = Obj(0)
End If
@@ -265,6 +270,8 @@ Public Class PropertyValues
Return oResults
End If
Next
Return New List(Of Object) From {Obj}

View File

@@ -0,0 +1,98 @@
Imports DigitalData.Modules.Interfaces.ZUGFeRDInterface
Imports DigitalData.Modules.Logging
Public Class Validator
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Public Sub New(pLogConfig As LogConfig)
_logConfig = pLogConfig
_logger = pLogConfig.GetLogger()
End Sub
Public Function ValidateZUGFeRDDocument(pResult As ZugferdResult) As ZugferdResult
ValidateDecimalNodes(pResult)
ValidateCurrencyNodes(pResult)
Return pResult
End Function
Private Sub ValidateDecimalNodes(ByRef pResult As ZugferdResult)
Try
Dim oDecimalNodes = pResult.XElementObject.Descendants().
Where(Function(n) n.Name.ToString.EndsWith("Amount") Or n.Name.ToString.EndsWith("Percent"))
For Each oNode As XElement In oDecimalNodes
Dim oParsedValue As Decimal = 0.0
If Decimal.TryParse(oNode.Value, oParsedValue) = False Then
pResult.ValidationErrors.Add(New ZugferdValidationError() With {
.ElementName = oNode.Name.LocalName,
.ElementValue = oNode.Value,
.ErrorMessage = "Value could not be parsed as Decimal"
})
End If
Next
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
Private Sub ValidateCurrencyNodes(ByRef pResult As ZugferdResult)
' CurrencyCode Nodes
Try
Dim oCurrencyCodeNodes = pResult.XElementObject.Descendants().
Where(Function(n) n.Name.ToString.EndsWith("CurrencyCode"))
For Each oNode As XElement In oCurrencyCodeNodes
Dim oValid = ValidateCurrencyCode(oNode.Value)
If oValid = False Then
pResult.ValidationErrors.Add(New ZugferdValidationError() With {
.ElementName = oNode.Name.LocalName,
.ElementValue = oNode.Value,
.ErrorMessage = "Invalid CurrencyCode. Only 3-Character codes are allowed."
})
End If
Next
Catch ex As Exception
_logger.Error(ex)
End Try
' currencyID
Try
Dim oCurrencyIDNodes = pResult.XElementObject.Descendants().
Where(Function(n) n.Attributes.Any(Function(a) a.Name.LocalName = "currencyID"))
For Each oNode As XElement In oCurrencyIDNodes
Dim oCurrencyID As String = oNode.Attribute("currencyID")?.Value
' CurrencyID is optional per spec
If String.IsNullOrWhiteSpace(oCurrencyID) Then
Continue For
End If
Dim oValid = ValidateCurrencyCode(oCurrencyID)
If oValid = False Then
pResult.ValidationErrors.Add(New ZugferdValidationError() With {
.ElementName = oNode.Name.LocalName,
.ElementValue = oCurrencyID,
.ErrorMessage = "Invalid currencyID. Only 3-Character codes or empty values are allowed."
})
End If
Next
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
Private Function ValidateCurrencyCode(pValue As String) As Boolean
Dim oValueRegex As New Text.RegularExpressions.Regex("[A-Z]{3}")
If oValueRegex.IsMatch(pValue) = False Then
Return False
End If
Return True
End Function
End Class

View File

@@ -330,6 +330,17 @@ Namespace ZUGFeRD.Version2_1_1
Private directDebitMandateIDField As IDType
Private descriptionField As TextType
Public Property Description As TextType
Get
Return descriptionField
End Get
Set
Me.descriptionField = Value
End Set
End Property
'''<remarks/>
Public Property DueDateDateTime() As DateTimeType
Get
@@ -363,7 +374,7 @@ Namespace ZUGFeRD.Version2_1_1
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute("DateTimeString")>
Public Property Item() As DateTimeTypeDateTimeString
Public Property DateTimeString() As DateTimeTypeDateTimeString
Get
Return Me.itemField
End Get
@@ -481,6 +492,28 @@ Namespace ZUGFeRD.Version2_1_1
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute([Namespace]:="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:10" &
"")>
Partial Public Class CreditorFinancialInstitutionType
Private bICIDField As IDType
'''<remarks/>
Public Property BICID() As IDType
Get
Return Me.bICIDField
End Get
Set
Me.bICIDField = Value
End Set
End Property
End Class
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute([Namespace]:="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:10" &
"0")>
Partial Public Class DebtorFinancialAccountType
@@ -581,10 +614,14 @@ Namespace ZUGFeRD.Version2_1_1
Private typeCodeField As PaymentMeansCodeType
Private informationField As TextType
Private payerPartyDebtorFinancialAccountField As DebtorFinancialAccountType
Private payeePartyCreditorFinancialAccountField As CreditorFinancialAccountType
Private payeeSpecifiedCreditorFinancialInstitutionField As CreditorFinancialInstitutionType
'''<remarks/>
Public Property TypeCode() As PaymentMeansCodeType
Get
@@ -595,6 +632,16 @@ Namespace ZUGFeRD.Version2_1_1
End Set
End Property
'''<remarks/>
Public Property Information() As TextType
Get
Return Me.informationField
End Get
Set
Me.informationField = Value
End Set
End Property
'''<remarks/>
Public Property PayerPartyDebtorFinancialAccount() As DebtorFinancialAccountType
Get
@@ -614,6 +661,16 @@ Namespace ZUGFeRD.Version2_1_1
Me.payeePartyCreditorFinancialAccountField = Value
End Set
End Property
'''<remarks/>
Public Property PayeeSpecifiedCreditorFinancialInstitution() As CreditorFinancialInstitutionType
Get
Return Me.payeeSpecifiedCreditorFinancialInstitutionField
End Get
Set
Me.payeeSpecifiedCreditorFinancialInstitutionField = Value
End Set
End Property
End Class
'''<remarks/>
@@ -1207,7 +1264,7 @@ Namespace ZUGFeRD.Version2_1_1
Private specifiedTradeAllowanceChargeField() As TradeAllowanceChargeType
Private specifiedTradePaymentTermsField As TradePaymentTermsType
Private specifiedTradePaymentTermsField() As TradePaymentTermsType
Private specifiedTradeSettlementHeaderMonetarySummationField As TradeSettlementHeaderMonetarySummationType
@@ -1299,7 +1356,8 @@ Namespace ZUGFeRD.Version2_1_1
End Property
'''<remarks/>
Public Property SpecifiedTradePaymentTerms() As TradePaymentTermsType
<System.Xml.Serialization.XmlElementAttribute("SpecifiedTradePaymentTerms")>
Public Property SpecifiedTradePaymentTerms() As TradePaymentTermsType()
Get
Return Me.specifiedTradePaymentTermsField
End Get
@@ -4100,171 +4158,171 @@ Namespace ZUGFeRD.Version2_1_1
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("80")>
Item80
Item80 = 80
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("81")>
Item81
Item81 = 81
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("82")>
Item82
Item82 = 82
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("83")>
Item83
Item83 = 83
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("84")>
Item84
Item84 = 84
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("130")>
Item130
Item130 = 130
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("202")>
Item202
Item202 = 202
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("203")>
Item203
Item203 = 203
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("204")>
Item204
Item204 = 204
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("211")>
Item211
Item211 = 211
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("261")>
Item261
Item261 = 261
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("262")>
Item262
Item262 = 262
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("295")>
Item295
Item295 = 295
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("296")>
Item296
Item296 = 296
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("308")>
Item308
Item308 = 308
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("325")>
Item325
Item325 = 325
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("326")>
Item326
Item326 = 326
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("380")>
Item380
Item380 = 380
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("381")>
Item381
Item381 = 381
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("383")>
Item383
Item383 = 383
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("384")>
Item384
Item384 = 384
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("385")>
Item385
Item385 = 385
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("386")>
Item386
Item386 = 386
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("387")>
Item387
Item387 = 387
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("388")>
Item388
Item388 = 388
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("389")>
Item389
Item389 = 389
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("390")>
Item390
Item390 = 390
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("393")>
Item393
Item393 = 393
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("394")>
Item394
Item394 = 394
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("395")>
Item395
Item395 = 395
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("396")>
Item396
Item396 = 396
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("420")>
Item420
Item420 = 420
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("456")>
Item456
Item456 = 456
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("457")>
Item457
Item457 = 457
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("458")>
Item458
Item458 = 458
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("527")>
Item527
Item527 = 527
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("575")>
Item575
Item575 = 575
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("623")>
Item623
Item623 = 623
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("633")>
Item633
Item633 = 633
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("751")>
Item751
Item751 = 751
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("780")>
Item780
Item780 = 780
'''<remarks/>
<System.Xml.Serialization.XmlEnumAttribute("935")>
Item935
Item935 = 935
End Enum
'''<remarks/>

View File

@@ -1,8 +1,14 @@
Public Class XmlItemProperty
Public IsRequired As Boolean
Public IsGrouped As Boolean
Public TableName As String
Public TableColumn As String
Public Description As String
Public IsRequired As Boolean
Public IsGrouped As Boolean
Public GroupScope As String
''' <summary>
''' Document version, eg. ZUGFeRD Schema version
''' </summary>
Public Specification As String
End Class

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net461" />
<package id="NLog" version="4.7.15" targetFramework="net461" />
<package id="NLog" version="5.0.5" targetFramework="net461" />
</packages>

View File

@@ -1,223 +0,0 @@
Option Explicit On
Imports System.IO
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Jobs
Imports DigitalData.Modules.Config
Imports DigitalData.Modules.Logging
Imports Newtonsoft.Json.Linq
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text.RegularExpressions
Imports DigitalData.Modules.Database
Imports System.Data
Public Class GraphQLJob
Inherits JobBase
Implements IJob(Of GraphQLArgs)
Private _GraphQL As GraphQLInterface = Nothing
Private Const PLACEHOLDER_STATIC = "STATIC:"
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer)
MyBase.New(LogConfig, Nothing, MSSQL)
End Sub
Public Sub Start(Args As GraphQLArgs) Implements IJob(Of GraphQLArgs).Start
Try
Dim oConfigPath As String = Args.QueryConfigPath
Dim oConfigManager As New ConfigManager(Of GraphQLConfig)(_LogConfig, oConfigPath)
With oConfigManager.Config
_GraphQL = New GraphQLInterface(_LogConfig, .BaseUrl, .Email, .Password, .CertificateFingerprint)
End With
' Login to get cookie
_Logger.Debug("Logging in")
Dim oLoginResponse = _GraphQL.Login()
' save cookie for future requests
_GraphQL.SaveCookies(oLoginResponse.Cookies.Item(0))
_Logger.Debug("Loading Queries")
' Load query data from TBCUST_JOBRUNNER_QUERY
Dim oQueryTable As DataTable = _MSSQL.GetDatatable("SELECT * FROM TBCUST_JOBRUNNER_QUERY ORDER BY OPERATION_NAME, CLEAR_BEFORE_FILL ASC")
Dim oQueryList As New List(Of GraphQL.Query)
' Save query data to business objects
For Each oRow As DataRow In oQueryTable.Rows
Dim oQuery As New GraphQL.Query With {
.Id = oRow.Item("GUID"),
.Name = oRow.Item("TITLE"),
.ClearBeforeFill = oRow.Item("CLEAR_BEFORE_FILL"),
.ConnectionId = oRow.Item("CON_ID"), ' TODO: Connection String?
.DestinationTable = oRow.Item("DESTINATION_TABLE"),
.OperationName = oRow.Item("OPERATION_NAME"),
.MappingBasePath = oRow.Item("MAPPING_BASE_PATH"),
.QueryString = oRow.Item("QUERY_STRING"),
.QueryConstraint = oRow.Item("QUERY_CONSTRAINT")
}
oQueryList.Add(oQuery)
Next
_Logger.Debug("Getting the data from GraphQL")
For Each oQuery As GraphQL.Query In oQueryList
Try
_Logger.NewBlock($"Query [{oQuery.Name}]")
Dim oConnectionId As Integer = oQuery.ConnectionId
Dim oConnectionString = _MSSQL.Get_ConnectionStringforID(oConnectionId)
Dim oDatabase As New MSSQLServer(_LogConfig, oConnectionString)
' Reset all records to status = 0
_Logger.Info("Resetting data with constraint [{1}]", oQuery.Name, oQuery.QueryConstraint)
Dim oResetSQL = $"UPDATE {oQuery.DestinationTable} SET STATUS = 0"
If oQuery.QueryConstraint <> String.Empty Then
oResetSQL &= $" WHERE {oQuery.QueryConstraint}"
End If
_MSSQL.ExecuteNonQuery(oResetSQL)
_Logger.Info("Getting data..", oQuery.Name)
' get the data from GraphQL
Dim oDataResponse = _GraphQL.GetData(oQuery.QueryString, oQuery.OperationName)
Dim oResult As String
' write data to string
Using oStream = oDataResponse.GetResponseStream()
Using oReader As New StreamReader(oStream)
oResult = oReader.ReadToEnd()
End Using
End Using
' Fill the query object with field mapping data from TBCUST_JOBRUNNER_QUERY_MAPPING
Dim oSQL As String = "SELECT t2.* FROM TBCUST_JOBRUNNER_QUERY_MAPPING t
JOIN TBCUST_JOBRUNNER_MAPPING t2 ON t.MAPPING_ID = t2.GUID
WHERE t.QUERY_ID = {0}"
Dim oMappingTable As DataTable = _MSSQL.GetDatatable(String.Format(oSQL, oQuery.Id))
For Each oMapping As DataRow In oMappingTable.Rows
oQuery.MappingFields.Add(New GraphQL.FieldMapping With {
.DestinationColumn = oMapping.Item("DestinationColumn"),
.SourcePath = oMapping.Item("SourcePath")
})
Next
' Handle the response from GraphQL and insert Data
Dim oQueryHandleResult = HandleResponse(oResult, oQuery, oDatabase)
If IsNothing(oQueryHandleResult) Then
Continue For
End If
' Finally delete all old records
Dim oDeleteSQL = $"DELETE FROM {oQuery.DestinationTable} WHERE STATUS = 0"
If oQuery.QueryConstraint <> String.Empty Then
oDeleteSQL &= $" AND {oQuery.QueryConstraint}"
End If
_Logger.Info("Success, deleting old records..", oQuery.Name)
_MSSQL.ExecuteNonQuery(oDeleteSQL)
Catch ex As Exception
_Logger.Warn("Error while getting Data for Name/OperationName [{0}]/[{1}]", oQuery.Name, oQuery.OperationName)
_Logger.Error(ex)
_Logger.Info("Failure, deleting new records..", oQuery.Name)
' If a crash happens, delete all records which were inserted in this run,
' thus going back to the previous state
Dim oDeleteSQL = $"DELETE FROM {oQuery.DestinationTable} WHERE STATUS = 1"
If oQuery.QueryConstraint <> String.Empty Then
oDeleteSQL &= $" AND {oQuery.QueryConstraint}"
End If
_MSSQL.ExecuteNonQuery(oDeleteSQL)
Finally
_Logger.EndBlock()
End Try
Next
' logout
_Logger.Debug("Logging out")
Dim oLogoutResponse = _GraphQL.Logout()
Catch ex As Exception
_Logger.Error(ex)
Throw ex
End Try
End Sub
Private Function HandleResponse(JsonString As String, QueryData As GraphQL.Query, DB As Database.MSSQLServer) As GraphQL.Query
Dim oObj As JObject = JObject.Parse(JsonString)
Dim oResultList As JToken
If _GraphQL.ReadJSONPathFragmented(oObj, QueryData.MappingBasePath) = False Then
_Logger.Warn("There is an error in the MappingBasePath [{1}] configuration of query [{0}]", QueryData.Name, QueryData.MappingBasePath)
End If
Try
oResultList = oObj.SelectToken(QueryData.MappingBasePath, errorWhenNoMatch:=True)
Catch ex As Exception
_Logger.Warn("HandleResponse: Could not find BasePath: [{0}] for query [{1}]", QueryData.MappingBasePath, QueryData.Name)
_Logger.Error(ex)
Return Nothing
End Try
If oResultList Is Nothing Then
_Logger.Warn("HandleResponse: Could not find BasePath: [{0}] for query [{1}]", QueryData.MappingBasePath, QueryData.Name)
Return Nothing
End If
_Logger.Info("HandleResponse: Processing Queue [{0}] with [{1}] Items", QueryData.Name, oResultList.Count)
For Each oResultItem As JToken In oResultList
Try
Dim oValues As New List(Of String)
Dim oKeys As New List(Of String)
For Each oMapping In QueryData.MappingFields
Dim oValue As String = String.Empty
If oMapping.SourcePath.StartsWith(PLACEHOLDER_STATIC) Then
oValue = oMapping.SourcePath.Replace(PLACEHOLDER_STATIC, String.Empty)
Else
Dim oToken = oResultItem.SelectToken(oMapping.SourcePath)
If oToken Is Nothing Then
_Logger.Warn("HandleResponse: Could not find value at SourcePath: {0}", oMapping.SourcePath)
oValue = String.Empty
Else
oValue = oToken.ToString
End If
End If
oValues.Add(oValue)
oKeys.Add(oMapping.DestinationColumn)
Next
Dim oColumnValues = oValues.
Select(Function(Value) Regex.Replace(Value, "'", "''")).
Select(Function(Value) $"'{Value}'").
ToList()
Dim oValueString = String.Join(",", oColumnValues)
Dim oColumns = String.Join(",", oKeys.ToArray)
Dim oSQL As String = $"INSERT INTO {QueryData.DestinationTable} ({oColumns}) VALUES ({oValueString})"
DB.ExecuteNonQuery(oSQL)
Catch ex As Exception
_Logger.Error(ex)
End Try
Next
Return QueryData
End Function
Public Function ShouldStart(Arguments As GraphQLArgs) As Boolean Implements IJob(Of GraphQLArgs).ShouldStart
Return Arguments.Enabled
End Function
End Class

View File

@@ -1,5 +0,0 @@
Public Class EmailData
Public Attachment As String = ""
Public Subject As String
Public From As String
End Class

View File

@@ -1,203 +0,0 @@
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Database
Imports System.Data
Imports System.IO
Imports System.Data.SqlClient
Public Class EmailFunctions
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Private ReadOnly _mssql As MSSQLServer
Private ReadOnly _firebird As Firebird
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer, Firebird As Firebird)
_logConfig = LogConfig
_logger = _logConfig.GetLogger()
_mssql = MSSQL
_firebird = Firebird
End Sub
Public Sub AddToEmailQueueFB(MessageId As String, BodyText As String, EmailData As EmailData, NamePortal As String)
If EmailData Is Nothing Then
_logger.Warn("EmailData is empty. Email will not be sent!")
Exit Sub
End If
Try
Dim oJobId = RandomValue(1, 10000)
Dim oReference = MessageId
Dim oEmailTo = ""
Dim oSubject = EmailStrings.EMAIL_SUBJECT_REJECTED.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal)
Dim oAccountId = 1
Dim oCreatedWho = "ZUGFeRD Service"
Dim oFinalBodyText = String.Format(EmailStrings.EMAIL_WRAPPING_TEXT.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal), BodyText)
Dim oEmailAddress = EmailData.From
Dim oAttachment = EmailData.Attachment
If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
_logger.Warn("Could not find email-address for MessageId {0}", MessageId)
oEmailTo = String.Empty
Else
oEmailTo = oEmailAddress
End If
_logger.Debug("Generated Email:")
_logger.Debug("To: {0}", oEmailTo)
_logger.Debug("Subject: {0}", oSubject)
_logger.Debug("Body {0}", oFinalBodyText)
Dim osql = $"select * from TBEDM_EMAIL_QUEUE where REFERENCE1 = '{oReference} and EMAIL_TO = ''{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
Dim oDTResult As DataTable = _firebird.GetDatatable(osql)
If oDTResult.Rows.Count = 0 Then
Dim oSQLInsert = $"INSERT INTO TBEDM_EMAIL_QUEUE "
oSQLInsert &= "(JOB_ID, REFERENCE1, EMAIL_ACCOUNT_ID, EMAIL_TO, EMAIL_SUBJ, EMAIL_BODY, CREATEDWHO, EMAIL_ATTMT1) VALUES "
oSQLInsert &= $"({oJobId}, '{oReference}', {oAccountId}, '{oEmailTo}', '{oSubject}', '{oFinalBodyText.Replace("'", "''")}', '{oCreatedWho}', '{oAttachment}')"
_firebird.ExecuteNonQuery(oSQLInsert)
_logger.Debug("Email Queue updated for MessageId {0}.", MessageId, oEmailTo)
Else
_logger.Debug("Email has already been sent!!")
End If
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer, NamePortal As String)
If pEmailData Is Nothing Then
_logger.Warn("EmailData is empty. Email will not be sent!")
Exit Sub
End If
Try
Dim oJobId = RandomValue(1, 10000)
Dim oReference = MessageId
Dim oEmailTo = ""
Dim oSubject = EmailStrings.EMAIL_SUBJECT_REJECTED.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal)
Dim oCreatedWho = "ZUGFeRD Service"
Dim oMaskedBodyText = BodyText.Replace("'", "''")
Dim oSubjectBodyText = String.Format(EmailStrings.EMAIL_SUBJECT_TEXT.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal), pEmailData.Subject).Replace("'", "''")
Dim oCompleteBodyText = oMaskedBodyText & oSubjectBodyText
Dim oFinalBodyText = String.Format(EmailStrings.EMAIL_WRAPPING_TEXT.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal), oCompleteBodyText)
Dim oEmailAddress = pEmailData.From
Dim oAttachment = pEmailData.Attachment
If oAttachment <> String.Empty Then
_logger.Debug($"Attachment_String [{oAttachment}]!")
If IO.File.Exists(oAttachment) = False Then
_logger.Info($"Attachment.File [{oAttachment}] is not existing!!!")
End If
End If
If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
_logger.Warn("Could not find email-address for MessageId {0}", MessageId)
oEmailTo = String.Empty
Else
oEmailTo = oEmailAddress
End If
_logger.Debug("Generated Email:")
_logger.Debug("To: {0}", oEmailTo)
_logger.Debug("Subject: {0}", oSubject)
_logger.Debug("Body {0}", oFinalBodyText)
Dim osql = $"Select MAX(GUID) FROM TBEMLP_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
Dim oHistoryID = _mssql.GetScalarValue(osql)
'osql = $"select * from TBEMLP_EMAIL_OUT where REFERENCE_ID = {oHistoryID} and EMAIL_ADRESS = '{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
'Dim oDTResult As DataTable = _mssql.GetDatatable(osql)
If IsNumeric(oHistoryID) Then
Dim oInsert = $"INSERT INTO [dbo].[TBEMLP_EMAIL_OUT] (
[REMINDER_TYPE_ID]
,[SENDING_PROFILE]
,[REFERENCE_ID]
,[REFERENCE_STRING]
,[WF_ID]
,[EMAIL_ADRESS]
,[EMAIL_SUBJ]
,[EMAIL_BODY]
,[COMMENT]
,[ADDED_WHO]
,EMAIL_ATTMT1)
VALUES
(77
,{pEmailAccountId}
,{oHistoryID}
,'{MessageId}'
,77
,'{oEmailTo}'
,'{oSubject}'
,'{oFinalBodyText}'
,'{SourceProcedure}'
,'{oCreatedWho}'
,'{oAttachment}')"
_mssql.ExecuteNonQuery(oInsert)
Else
'If oDTResult.Rows.Count = 0 Then
' _logger.Debug("Email has already been sent!!")
'Else
_logger.Warn("Could not get oHistoryID in AddToEmailQueueMSSQL!!")
' End If
End If
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
Public Function GetEmailDataForMessageId(MessageId As String) As EmailData
Dim oSQL = $"SELECT EMAIL_FROM, EMAIL_SUBJECT, EMAIL_ATTMT1 FROM TBEDM_EMAIL_PROFILER_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
Try
Dim oDatatable = _firebird.GetDatatable(oSQL)
Dim oRow As DataRow
If oDatatable.Rows.Count = 0 Then
_logger.Warn("Got no results for MessageId {0}", MessageId)
Return Nothing
ElseIf oDatatable.Rows.Count > 1 Then
_logger.Warn("Got too many results for MessageId {0}. Using last row.", MessageId)
End If
_logger.Debug("Got Email Data for FileId {0}", MessageId)
oRow = oDatatable.Rows.Item(oDatatable.Rows.Count - 1)
Return New EmailData() With {
.From = oRow.Item("EMAIL_FROM"),
.Attachment = oRow.Item("EMAIL_ATTMT1"),
.Subject = oRow.Item("EMAIL_SUBJECT")
}
Catch ex As Exception
_logger.Warn("Could not fetch Email Data for FileId {0}", MessageId)
Return Nothing
End Try
End Function
Public Function GetOriginalEmailPath(OriginalEmailDirectory As String, MessageId As String) As String
Dim oAttachmentDirectory = OriginalEmailDirectory
Dim oAttachmentFile = MessageId & ".eml"
Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
If File.Exists(oAttachmentPath) Then
Return oAttachmentPath
Else
_logger.Warn("Email File {0} does not exist. Empty String will be returned.", oAttachmentPath)
Return String.Empty
End If
End Function
Public Function GetEmailPathWithSubjectAsName(RejectedEmailDirectory As String, UncleanedSubject As String) As String
Dim oCleanSubject = String.Join("", UncleanedSubject.Split(Path.GetInvalidPathChars()))
Dim oAttachmentDirectory = RejectedEmailDirectory
Dim oAttachmentFile = oCleanSubject & ".eml"
Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
Return oAttachmentPath
End Function
Private Function RandomValue(lowerBound As Integer, upperBound As Integer) As Integer
Dim oRandomValue = CInt(Math.Floor((upperBound - lowerBound + 1) * Rnd())) + lowerBound
Return oRandomValue
End Function
End Class

View File

@@ -1,825 +0,0 @@
Imports System.Collections.Generic
Imports System.Data
Imports System.IO
Imports System.Linq
Imports System.Security.Cryptography
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Jobs.Exceptions
Imports DigitalData.Modules.Logging
Imports FirebirdSql.Data.FirebirdClient
Imports System.Data.SqlClient
Public Class ImportZUGFeRDFiles
Implements IJob
Public Const ZUGFERD_IN = "ZUGFeRD in"
Public Const ZUGFERD_ERROR = "ZUGFeRD Error"
Public Const ZUGFERD_SUCCESS = "ZUGFeRD Success"
Public Const ZUGFERD_EML = "ZUGFeRD Eml"
Public Const ZUGFERD_REJECTED_EML = "ZUGFeRD Eml Rejected"
Public Const ZUGFERD_ATTACHMENTS = "ZUGFeRD Attachments"
Public Const ZUGFERD_NO_ZUGFERD = "Non-ZUGFeRD Files"
Public HISTORY_ID As Integer
Private Const DIRECTORY_DONT_MOVE = "DIRECTORY_DONT_MOVE"
' List of allowed extensions for PDF/A Attachments
' This list should not contain xml so the zugferd xml file will be filtered out
Private ReadOnly AllowedExtensions As List(Of String) = New List(Of String) From {"docx", "doc", "pdf", "xls", "xlsx", "ppt", "pptx", "txt"}
Private ReadOnly _logger As Logger
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _zugferd As ZUGFeRDInterface
Private ReadOnly _firebird As Firebird
Private ReadOnly _filesystem As Filesystem.File
Private ReadOnly _EmailOutAccountId As Integer
Private ReadOnly _mssql As MSSQLServer
Private ReadOnly _email As EmailFunctions
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, pEmailOutAccount As Integer, pPortalName As String, Optional MSSQL As MSSQLServer = Nothing)
_logConfig = LogConfig
_logger = LogConfig.GetLogger()
_firebird = Firebird
_filesystem = New Filesystem.File(_logConfig)
_mssql = MSSQL
_EmailOutAccountId = pEmailOutAccount
_email = New EmailFunctions(LogConfig, _mssql, _firebird)
_logger.Debug("Registering GDPicture License")
If _mssql IsNot Nothing Then
Dim oSQL = "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'"
Dim oLicenseKey As String = _mssql.GetScalarValue(oSQL)
_zugferd = New ZUGFeRDInterface(_logConfig, oLicenseKey)
Else
_logger.Warn("GDPicture License could not be registered! MSSQL is not enabled!")
Throw New ArgumentNullException("MSSQL")
End If
End Sub
Private Function MoveAndRenameEmailToRejected(Args As WorkerArgs, MessageId As String) As EmailData
Dim oEmailData = _email.GetEmailDataForMessageId(MessageId)
Dim oSource = _email.GetOriginalEmailPath(Args.OriginalEmailDirectory, MessageId)
Dim oDateSubDirectoryName As String = Now.ToString("yyyy-MM-dd")
Dim oDestination As String
Dim oRejectedDirectory As String = Path.Combine(Args.RejectedEmailDirectory, oDateSubDirectoryName)
' Create the destination directory if it does not exist
If Not Directory.Exists(oRejectedDirectory) Then
Try
Directory.CreateDirectory(oRejectedDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
' If oEmailData is Nothing, TBEDM_EMAIL_PROFILER_HISTORY for MessageId was not found.
' This only should happen when testing and db-tables are deleted frequently
If oEmailData Is Nothing Then
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, MessageId)
Else
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, oEmailData.Subject)
End If
_logger.Debug("Destination for eml file is {0}", oDestination)
Dim oFinalFileName = _filesystem.GetVersionedFilename(oDestination)
_logger.Debug("Versioned filename for eml file is {0}", oFinalFileName)
If oEmailData Is Nothing Then
_logger.Warn("Could not get Email Data from firebird-database. File {0} will not be moved!", oSource)
Return Nothing
End If
Try
_logger.Info("Moving email from {0} to {1}", oSource, oFinalFileName)
IO.File.Move(oSource, oFinalFileName)
oEmailData.Attachment = oFinalFileName
Catch ex As Exception
_logger.Warn("File {0} could not be moved! Original Filename will be used!", oSource)
_logger.Error(ex)
oEmailData.Attachment = oSource
End Try
Return oEmailData
End Function
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String, Transaction As SqlTransaction)
Try
'PRCUST_ADD_HISTORY_STATE: @MessageID VARCHAR(250), @TITLE1 VARCHAR(250), @TITLE2 VARCHAR(250)
Dim oSQL = $"EXEC PRCUST_ADD_HISTORY_STATE '{oMessageID}','{oTitle}','{oTitle1}','{oComment.Replace("'", "''")}'"
_mssql.ExecuteNonQuery(oSQL, Transaction)
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
Public Sub Start(Arguments As Object) Implements IJob.Start
Dim oArgs As WorkerArgs = Arguments
Dim oPropertyExtractor = New PropertyValues(_logConfig)
Dim oAttachmentExtractor = New PDFEmbeds(_logConfig)
_logger.Debug("Starting Job {0}", [GetType].Name)
Try
For Each oPath As String In oArgs.WatchDirectories
Dim oDirInfo As New DirectoryInfo(oPath)
_logger.Debug($"Start processing directory {oDirInfo.FullName}")
If oDirInfo.Exists Then
' Filter out *.lock files
Dim oFiles As List(Of FileInfo) = oDirInfo.
GetFiles().
Where(Function(f) Not f.Name.EndsWith(".lock")).
ToList()
Dim oFileCount = oFiles.Count
Dim oCurrentFileCount = 0
If oFileCount = 0 Then
_logger.Debug("No files to process.")
Continue For
Else
_logger.Info("Found {0} files", oFileCount)
End If
' Group files by messageId
Dim oGrouped As Dictionary(Of String, List(Of FileInfo)) = _zugferd.FileGroup.GroupFiles(oFiles)
_logger.Info("Found {0} file groups", oGrouped.Count)
' Process each file group together
For Each oFileGroup In oGrouped
' Start a new transaction for each file group.
' This way we can rollback database changes for the whole filegroup in case something goes wrong.
Dim oFBConnection As FbConnection = _firebird.GetConnection()
Dim oFBTransaction As FbTransaction = oFBConnection.BeginTransaction()
Dim oSQLConnection As SqlConnection = _mssql.GetConnection()
Dim oSQLTransaction As SqlTransaction = oSQLConnection?.BeginTransaction()
If oSQLConnection Is Nothing Then
_logger.Warn("SQL Connection was not set. No INSERTs for MSSQL Server will be performed!")
oArgs.InsertIntoSQLServer = False
End If
' Count the amount of ZUGFeRD files
Dim oZUGFeRDCount As Integer = 0
' Set the default Move Directory
Dim oMoveDirectory As String = oArgs.ErrorDirectory
' Flag to save if the whole process was a success.
' Will be set only at the end of the function if no error occurred.
Dim oIsSuccess As Boolean = False
' Flag to save if the occurred error (if any) was expected
' Used to determine if transactions should be committed or not
Dim oExpectedError As Boolean = True
' Create file lists
Dim oFileGroupFiles As List(Of FileInfo) = oFileGroup.Value
Dim oEmailAttachmentFiles As New List(Of FileInfo)
Dim oEmbeddedAttachmentFiles As New List(Of PDFEmbeds.EmbeddedFile)
Dim oMessageId As String = oFileGroup.Key
Dim oMissingProperties As New List(Of String)
Dim oMD5CheckSum As String = String.Empty
_logger.NewBlock($"Message Id {oMessageId}")
_logger.Info("Start processing file group {0}", oMessageId)
Try
For Each oFile In oFileGroupFiles
' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the
' different versions of ZUGFeRD and the type is unknown at compile-time.
Dim oDocument As Object
' Start a global group counter for each file
Dim oGlobalGroupCounter = 0
' Clear missing properties for the new file
oMissingProperties = New List(Of String)
oCurrentFileCount += 1
' Only pdf files are allowed from here on
If Not oFile.Name.ToUpper.EndsWith(".PDF") Then
_logger.Debug("Skipping non-pdf file {0}", oFile.Name)
oEmailAttachmentFiles.Add(oFile)
' Checking filesize for attachment files
If Check_FileSize(oFile, oArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", oFile.Name, oArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(oFile.Name, oArgs.MaxAttachmentSizeInMegaBytes)
End If
Continue For
End If
_logger.Info("Start processing file {0}", oFile.Name)
' Checking filesize for pdf files
If Check_FileSize(oFile, oArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", oFile.Name, oArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(oFile.Name, oArgs.MaxAttachmentSizeInMegaBytes)
End If
Try
oDocument = _zugferd.ExtractZUGFeRDFileWithGDPicture(oFile.FullName)
Catch ex As ZUGFeRDExecption
Select Case ex.ErrorType
Case ZUGFeRDInterface.ErrorType.NoZugferd
_logger.Info("File [{0}] is not a valid ZUGFeRD document. Skipping.", oFile.Name)
oEmailAttachmentFiles.Add(oFile)
Continue For
Case ZUGFeRDInterface.ErrorType.NoValidZugferd
_logger.Warn("File [{0}] is an Incorrectly formatted ZUGFeRD document!", oFile.Name)
Throw New InvalidFerdException()
Case Else
_logger.Warn("Unexpected Error occurred while extracting ZUGFeRD Information from file {0}", oFile.Name)
Throw ex
End Select
End Try
' Extract all attachments with the extensions specified in `AllowedExtensions`.
' If you need to extract and use embedded xml files, you need to filter out the zugferd-invoice.xml yourself.
' Right now the zugferd-invoice.xml is filtered out because `AllowedExtensions` does not contain `xml`.
Dim oAttachments = oAttachmentExtractor.Extract(oFile.FullName, AllowedExtensions)
If oAttachments Is Nothing Then
_logger.Warn("Attachments for file [{0}] could not be extracted", oFile.FullName)
Else
oEmbeddedAttachmentFiles.AddRange(oAttachments)
End If
' Check the Checksum and rejection status
oMD5CheckSum = GenerateAndCheck_MD5Sum(oFile.FullName, oArgs.IgnoreRejectionStatus)
' Check if there are more than one ZUGFeRD files
If oZUGFeRDCount = 1 Then
Throw New TooMuchFerdsException()
End If
' Since extraction went well, increase the amount of ZUGFeRD files
oZUGFeRDCount += 1
' Check the document against the configured property map and return:
' - a List of valid properties
' - a List of missing properties
Dim oCheckResult = _zugferd.PropertyValues.CheckPropertyValues(oDocument, oArgs.PropertyMap, oMessageId)
_logger.Info("Properties checked: [{0}] missing properties / [{1}] valid properties found.", oCheckResult.MissingProperties.Count, oCheckResult.ValidProperties.Count)
If oCheckResult.MissingProperties.Count > 0 Then
_logger.Warn("[{0}] missing properties found. Exiting.", oCheckResult.MissingProperties.Count)
oMissingProperties = oCheckResult.MissingProperties
Throw New MissingValueException(oFile)
End If
_logger.Debug("No missing properties found. Continuing.")
Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{oMessageId}'"
Dim oStep As String
oStep = "Firebird TBEDMI_ITEM_VALUE Delete messageID Items"
Try
_firebird.ExecuteNonQueryWithConnection(oDelSQL, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
End Try
If oArgs.InsertIntoSQLServer = True Then
oStep = "MSSQL TBEDMI_ITEM_VALUE Delete messageID Items"
Try
_mssql.ExecuteNonQueryWithConnectionObject(oDelSQL, oSQLConnection, MSSQLServer.TransactionMode.ExternalTransaction, oSQLTransaction)
Catch ex As Exception
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
End Try
End If
For Each oProperty In oCheckResult.ValidProperties
Dim oGroupCounterValue = oProperty.GroupCounter
' If GroupCounter is -1, it means this is a default property that can only occur once.
' Set the actual inserted value to 0
If oGroupCounterValue = -1 Then
oGroupCounterValue = 0
End If
Dim oCommand = $"INSERT INTO {oProperty.TableName} (REFERENCE_GUID, ITEM_DESCRIPTION, ITEM_VALUE, GROUP_COUNTER,SPEC_NAME,IS_REQUIRED) VALUES
('{oMessageId}', '{oProperty.Description}', '{oProperty.Value.Replace("'", "''")}', {oGroupCounterValue},'{oProperty.TableColumn}','{oProperty.ISRequired}')"
_logger.Debug("Mapping Property [{0}] with value [{1}], Will be inserted into table [{2}]", oProperty.TableColumn, oProperty.Value.Replace("'", "''"), oProperty.TableName)
' Insert into SQL Server
If oArgs.InsertIntoSQLServer = True Then
Dim oResult = _mssql.ExecuteNonQueryWithConnectionObject(oCommand, oSQLConnection, MSSQLServer.TransactionMode.ExternalTransaction, oSQLTransaction)
If oResult = False Then
_logger.Warn($"SQL Command [{oCommand}] was not successful. Check the log.")
End If
End If
' Insert into Firebird
_firebird.ExecuteNonQueryWithConnection(oCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
Next
Next
'Check if there are no ZUGFeRD files
If oZUGFeRDCount = 0 Then
' If NonZugferdDirectory is not set, a NoFerdsException will be thrown and a rejection will be generated
' This is the default/initial behaviour.
If oArgs.NonZugferdDirectory Is Nothing OrElse oArgs.NonZugferdDirectory = String.Empty Then
Throw New NoFerdsException()
End If
' Also, if the directory is set but does not exist, still a rejection will be generated.
If Not IO.Directory.Exists(oArgs.NonZugferdDirectory) Then
Throw New NoFerdsException()
End If
' Only if the directory is set and does exist, it will be used and any file groups which
' do NOT CONTAIN ANY ZUGFERD DOCUMENTS, are moved to that directory.
Throw New NoFerdsAlternateException()
End If
'If no errors occurred...
'Log the History
If oMD5CheckSum <> String.Empty Then
Create_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS", oFBTransaction)
'Dim oInsertCommand = $"INSERT INTO TBEDM_ZUGFERD_HISTORY_IN (MESSAGE_ID, MD5HASH) VALUES ('{oMessageId}', '{oMD5CheckSum}')"
'_firebird.ExecuteNonQueryWithConnection(oInsertCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
'' History ID is only need in case of an error
'oFBTransaction.Commit()
'Try
' Dim oSQL = $"SELECT MAX(GUID) FROM TBEDM_ZUGFERD_HISTORY_IN WHERE MESSAGE_ID = '{oMessageId}'"
' HISTORY_ID = _firebird.GetScalarValue(oSQL)
'Catch ex As Exception
' HISTORY_ID = 0
'End Try
Else
Create_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)", oFBTransaction)
End If
oIsSuccess = True
oMoveDirectory = oArgs.SuccessDirectory
Catch ex As MD5HashException
_logger.Error(ex)
Dim oMessage = "REJECTED - Already processed (MD5Hash)"
Update_HistoryEntry(oMessageId, oMD5CheckSum, oMessage, oFBTransaction)
Dim oBody = EmailStrings.EMAIL_MD5_ERROR
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction)
Catch ex As InvalidFerdException
_logger.Error(ex)
' When InvalidFerdException is thrown, we don't have a MD5Hash yet.
' That 's why we set it to String.Empty here.
Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but incorrect format", oFBTransaction)
Dim oBody = EmailStrings.EMAIL_INVALID_DOCUMENT
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "", oSQLTransaction)
Catch ex As TooMuchFerdsException
_logger.Error(ex)
Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - More than one ZUGFeRD-document in email", oFBTransaction)
Dim oBody = EmailStrings.EMAIL_TOO_MUCH_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "", oSQLTransaction)
Catch ex As NoFerdsException
_logger.Error(ex)
Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - no ZUGFeRD-Document in email", oFBTransaction)
Dim oBody = EmailStrings.EMAIL_NO_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "", oSQLTransaction)
Catch ex As NoFerdsAlternateException
' TODO: Maybe dont even log this 'error', since it's not really an error and it might happen *A LOT*
_logger.Error(ex)
oMoveDirectory = oArgs.NonZugferdDirectory
Catch ex As MissingValueException
_logger.Error(ex)
Dim oMessage As String = ""
For Each prop In oMissingProperties
oMessage &= $"- {prop}"
Next
Create_HistoryEntry(oMessageId, oMD5CheckSum, $"REJECTED - Missing Required Properties: [{oMessage}]", oFBTransaction)
Dim oBody = CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage, oSQLTransaction)
Catch ex As FileSizeLimitReachedException
_logger.Error(ex)
Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - File size limit reached", oFBTransaction)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oKey = FileSizeLimitReachedException.KEY_FILENAME
Dim oFileExceedingThreshold As String = IIf(ex.Data.Contains(oKey), ex.Data.Item(oKey), "")
Dim oFileWithoutMessageId = oFileExceedingThreshold.
Replace(oMessageId, "").
Replace("~", "")
Dim oBody = String.Format(EmailStrings.EMAIL_FILE_SIZE_REACHED, oArgs.MaxAttachmentSizeInMegaBytes, oFileWithoutMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "FileSizeLimitReachedException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "FileSizeLimitReachedException", "Erlaubte Dateigröße überschritten", "", oSQLTransaction)
Catch ex As OutOfMemoryException
_logger.Warn("OutOfMemory Error occurred: {0}", ex.Message)
_logger.Error(ex)
' Send Email to Digital Data
Dim oBody = CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress,
.Subject = $"OutOfMemoryException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "OutOfMemoryException", _EmailOutAccountId, oArgs.NamePortal)
' Rollback Firebird
oFBTransaction.Rollback()
' Rollback MSSQL
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
oExpectedError = False
Catch ex As Exception
_logger.Warn("Unknown Error occurred: {0}", ex.Message)
_logger.Error(ex)
' Send Email to Digital Data
Dim oBody = CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress,
.Subject = $"UnhandledException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "UnhandledException", _EmailOutAccountId, oArgs.NamePortal)
' Rollback Firebird
oFBTransaction.Rollback()
' Rollback MSSQL
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
oExpectedError = False
Finally
Try
' If an application error occurred, dont move files so they will be processed again later
If oMoveDirectory = DIRECTORY_DONT_MOVE Then
_logger.Info("Application Error occurred. Files for message Id {0} will not be moved.", oMessageId)
Else
' Move all files of the current group
MoveFiles(oArgs, oMessageId, oFileGroupFiles, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess)
End If
_logger.Info("Finished processing file group {0}", oMessageId)
Catch ex As Exception
' Send Email to Digital Data
Dim oBody = CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress,
.Subject = $"FileMoveException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "FileMoveException", _EmailOutAccountId, oArgs.NamePortal)
_logger.Warn("Could not move files!")
_logger.Error(ex)
Throw ex
Finally
_logger.EndBlock()
End Try
Try
' If everything went OK or an expected error occurred,
' finally commit all changes To the Database
' ==================================================================
If oIsSuccess Or oExpectedError Then
' Commit SQL Transaction
oSQLTransaction.Commit()
' Commit Firebird Transaction
oFBTransaction.Commit()
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Transactions were not committed successfully.")
End Try
Try
oFBConnection.Close()
oSQLConnection.Close()
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Connections were not closed successfully.")
End Try
End Try
Next
End If
Next
_logger.Debug("Finishing Job {0}", Me.GetType.Name)
Catch ex As Exception
_logger.Error(ex)
_logger.Info("Job Failed! See error log for details")
End Try
End Sub
Private Sub MoveFiles(
Args As WorkerArgs,
MessageId As String,
Files As List(Of FileInfo),
AttachmentFiles As List(Of FileInfo),
EmbeddedAttachments As List(Of PDFEmbeds.EmbeddedFile),
MoveDirectory As String,
IsSuccess As Boolean)
Dim oFinalMoveDirectory As String = MoveDirectory
Dim oDateSubDirectoryName As String = Now.ToString("yyyy\\MM\\dd")
Dim oAttachmentDirectory As String = Path.Combine(oFinalMoveDirectory, Args.AttachmentsSubDirectory, oDateSubDirectoryName)
' Files will be moved to a subfolder for the current day if they are rejected
If Not IsSuccess Then
oFinalMoveDirectory = Path.Combine(oFinalMoveDirectory, oDateSubDirectoryName)
End If
' Create directories if they don't exist
If Not Directory.Exists(oFinalMoveDirectory) Then
Try
Directory.CreateDirectory(oFinalMoveDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
If Not Directory.Exists(oAttachmentDirectory) And AttachmentFiles.Count > 0 Then
Try
Directory.CreateDirectory(oAttachmentDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
' Filter out Attachments from `Files`
Dim oInvoiceFiles As List(Of FileInfo) = Files.Except(AttachmentFiles).ToList()
' Move PDF/A Files
For Each oFile In oInvoiceFiles
Try
Dim oFilePath = _filesystem.GetVersionedFilename(Path.Combine(oFinalMoveDirectory, oFile.Name))
_filesystem.MoveTo(oFile.FullName, oFilePath, oFinalMoveDirectory)
_logger.Info("File moved to {0}", oFilePath)
Catch ex As Exception
_logger.Warn("Could not move file {0}", oFile.FullName)
_logger.Error(ex)
End Try
Next
' Move non-PDF/A Email Attachments/Files
For Each oFile In AttachmentFiles
Try
Dim oFilePath = _filesystem.GetVersionedFilename(Path.Combine(oAttachmentDirectory, oFile.Name))
_filesystem.MoveTo(oFile.FullName, oFilePath, oAttachmentDirectory)
_logger.Info("Attachment moved to {0}", oFilePath)
Catch ex As Exception
_logger.Warn("Could not move attachment {0}", oFile.FullName)
_logger.Error(ex)
End Try
Next
' Write Embedded Files to disk
For Each oResult In EmbeddedAttachments
Try
Dim oFileName As String = $"{MessageId}~{oResult.FileName}"
Dim oFilePath As String = Path.Combine(oAttachmentDirectory, oFileName)
If Not File.Exists(oAttachmentDirectory) Then
Directory.CreateDirectory(oAttachmentDirectory)
End If
Using oWriter As New FileStream(oFilePath, FileMode.Create)
oWriter.Write(oResult.FileContents, 0, oResult.FileContents.Length)
_logger.Info("Embedded Attachment moved to {0}", oFilePath)
End Using
Catch ex As Exception
_logger.Warn("Could not save embedded attachment {0}", oResult.FileName)
_logger.Error(ex)
End Try
Next
_logger.Info("Finished moving files")
End Sub
Private Function CreateBodyForMissingProperties(OriginalFilename As String, MissingProperties As List(Of String)) As String
Dim oBody = String.Format(EmailStrings.EMAIL_MISSINGPROPERTIES_1, OriginalFilename)
If MissingProperties.Count > 0 Then
oBody &= $"{vbNewLine}{vbNewLine}"
oBody &= EmailStrings.EMAIL_MISSINGPROPERTIES_2
oBody &= $"{vbNewLine}{vbNewLine}"
For Each prop In MissingProperties
oBody &= $"- {prop}"
Next
End If
Return oBody
End Function
Private Function CreateBodyForUnhandledException(MessageId As String, Exception As Exception) As String
Dim oBody = String.Format(EmailStrings.EMAIL_UNHANDLED_EXCEPTION, MessageId, Exception.Message, Exception.StackTrace)
Return oBody
End Function
Private Function CreateMD5(ByVal Filename As String) As String
Try
Dim oMD5 As New MD5CryptoServiceProvider
Dim oHash As Byte()
Dim oHashString As String
Dim oResult As String = ""
Using oFileStream As New FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
oHash = oMD5.ComputeHash(oFileStream)
oHashString = BitConverter.ToString(oHash)
End Using
oResult = oHashString.Replace("-", "")
Return oResult
Catch ex As Exception
_logger.Error(ex)
Return ""
End Try
End Function
Private Function Create_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As FbTransaction) As Boolean
Try
Dim oConnection = _firebird.GetConnection()
Dim oSQL = $"INSERT INTO TBEDM_ZUGFERD_HISTORY_IN (COMMENT, MD5HASH, MESSAGE_ID) VALUES ('{Message}', '{MD5Checksum}', '{MessageId}')"
' 09.07.2021: This can't be in the transaction since the history
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
_firebird.ExecuteNonQueryWithConnection(oSQL, oConnection, Firebird.TransactionMode.WithTransaction)
' Close the connection
oConnection.Close()
If Message.Contains("REJECTED") Then
oSQL = $"UPDATE TBEMLP_HISTORY SET STATUS = 'REJECTED', COMMENT = '{Message}', CUST_REJECTED = 1,CUST_REJECTED_WHEN = GETDATE() WHERE EMAIL_MSGID = '{MessageId}'"
_mssql.ExecuteNonQuery(oSQL)
End If
Return True
Catch ex As Exception
_logger.Warn("History Entry count not be created for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
_logger.Error(ex)
Return False
End Try
End Function
Private Function Update_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As FbTransaction) As Boolean
Try
Dim oConnection = _firebird.GetConnection()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = '{Message}' WHERE MD5HASH = '{MD5Checksum}' AND MESSAGE_ID = '{MessageId}'"
_firebird.ExecuteNonQueryWithConnection(oSQL, oConnection, Firebird.TransactionMode.WithTransaction)
' Close the connection
oConnection.Close()
Return True
Catch ex As Exception
_logger.Warn("History Entry count not be updated for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
_logger.Error(ex)
Return False
End Try
End Function
''' <summary>
''' Generates the MD5 Checksum of a file and checks it against the histroy table TBEDM_ZUGFERD_HISTORY_IN
''' </summary>
''' <param name="pFilePath">The path of the file to be checked</param>
''' <param name="pIgnoreRejectionStatus">Should the check take into account the rejection status of the file?</param>
''' <returns>The MD5 Checksum of the file, or an empty string, if the Checksum could not be created</returns>
''' <exception cref="MD5HashException">Throws, when the file should be rejected, ie. if it already exists in the table</exception>
Private Function GenerateAndCheck_MD5Sum(pFilePath As String, pIgnoreRejectionStatus As Boolean) As String
Dim oMD5CheckSum = CreateMD5(pFilePath)
' Exit if MD5 could not be created
If oMD5CheckSum = String.Empty Then
_logger.Warn("MD5 Checksum is nothing for file [{0}]!", pFilePath)
Return oMD5CheckSum
End If
' Check if Checksum exists in History Table
Dim oCheckCommand = $"SELECT * FROM TBEDM_ZUGFERD_HISTORY_IN WHERE GUID = (SELECT MAX(GUID) FROM TBEDM_ZUGFERD_HISTORY_IN WHERE UPPER(MD5HASH) = UPPER('{oMD5CheckSum}'))"
Dim oTable As DataTable = _firebird.GetDatatable(oCheckCommand, Firebird.TransactionMode.NoTransaction)
' If History entries could not be fetched, just return the MD5 Checksum
If IsNothing(oTable) Then
_logger.Warn("Be careful: oExistsDT is nothing for file [{0}]!", pFilePath)
Return oMD5CheckSum
End If
' If Checksum does not exist in History entries, just return the MD5 Checksum
If oTable.Rows.Count = 0 Then
_logger.Debug("File [{0}] was not found in History!", pFilePath)
Return oMD5CheckSum
End If
' ====================================================
' Checksum exists in History entries, reject!
' ====================================================
Dim oRejected As Boolean
Dim oHistoryId As Integer
' Try to read Rejected Status and History Id
Try
Dim oRow As DataRow = oTable.Rows.Item(0)
oRejected = DirectCast(oRow.Item("REJECTED"), Boolean)
oHistoryId = oRow.Item("GUID")
Catch ex As Exception
_logger.Warn("Error while converting REJECTED: " & ex.Message)
oRejected = False
End Try
_logger.Info("File has already been processed...")
' If the file was already rejected, it is allowed to be processed again,
' even if the Checksum exists in the history entries (default case)
' Which means, if it was not rejected before, it will be rejected in any case!
'
' This logic can be overwritten by the IgnoreRejectionStatus parameter.
' If it is set to true, the file will be rejected if the file exists in the history entries,
' regardless of the rejected parameter.
If oRejected = True And pIgnoreRejectionStatus = True Then
_logger.Info("ZuGFeRDFile already has been processed, but formerly obviously was rejected!")
Else
Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}]")
End If
Return oMD5CheckSum
End Function
''' <summary>
''' Checks the size of the supplied file.
''' </summary>
''' <param name="pFileInfo"></param>
''' <param name="pMaxFileSizeInMegaBytes"></param>
''' <returns></returns>
Private Function Check_FileSize(pFileInfo As FileInfo, pMaxFileSizeInMegaBytes As Integer) As Boolean
_logger.Info("Checking Filesize of {0}", pFileInfo.Name)
_logger.Debug("Filesize threshold is {0} MB.", pMaxFileSizeInMegaBytes)
If pMaxFileSizeInMegaBytes <= 0 Then
_logger.Debug("Filesize is not configured. Skipping check.")
Return True
End If
Dim oMaxSize = pMaxFileSizeInMegaBytes * 1024 * 1024
If oMaxSize > 0 And pFileInfo.Length > oMaxSize Then
_logger.Debug("Filesize is bigger than threshold. Rejecting.")
Return False
Else
_logger.Debug("Filesize is smaller than threshold. All fine.")
Return True
End If
End Function
End Class

View File

@@ -1,15 +1,19 @@
Imports System.IO
Imports System.Collections.Generic
Imports System.IO
Imports DigitalData.Modules.Interfaces.ZUGFeRDInterface
Public Class Exceptions
Public Class MissingValueException
Inherits ApplicationException
Public ReadOnly File As FileInfo
Public ReadOnly MissingProperties As List(Of String)
Public Sub New(File As FileInfo)
MyBase.New()
Public Sub New(pFile As FileInfo, pMissingProperties As List(Of String))
MyBase.New($"Missing values in [{pFile.Name}]")
Me.File = File
Me.File = pFile
Me.MissingProperties = pMissingProperties
End Sub
End Class
@@ -40,6 +44,17 @@ Public Class Exceptions
End Sub
End Class
Public Class UnsupportedFerdException
Inherits ApplicationException
Public ReadOnly Property XmlFile As String
Public Sub New(pXmlFile As String)
MyBase.New("ZUGFeRD document found but is not supported!")
_XmlFile = pXmlFile
End Sub
End Class
Public Class NoFerdsException
Inherits ApplicationException
@@ -60,8 +75,11 @@ Public Class Exceptions
Public Class MD5HashException
Inherits ApplicationException
Public Sub New(pInfo As String)
MyBase.New(pInfo)
Public ReadOnly FileName As String
Public Sub New(pMessage As String, pFileName As String)
MyBase.New(pMessage)
FileName = pFileName
End Sub
End Class
End Class

Some files were not shown because too many files have changed in this diff Show More