diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml
index 04663dd9c..f822ba417 100644
--- a/.github/workflows/Build.yml
+++ b/.github/workflows/Build.yml
@@ -45,6 +45,11 @@ jobs:
dotnet-version: '6.0.x'
include-prerelease: false
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.100'
+
- name: Calculate environment variables
id: buildVariables
run: |
@@ -185,14 +190,14 @@ jobs:
$PushToAzureArgs += "--skip-duplicate"
}
- dotnet $PushToAzureArgs
+ dotnet $PushToAzureArgs || exit 1
$pushedToAzure += 1
if (!$IsPrerelease) {
- dotnet $PushToGitHubArgs
+ dotnet $PushToGitHubArgs || exit 1
$pushedToGitHub += 1
- dotnet $PushToNugetArgs
+ dotnet $PushToNugetArgs || exit 1
$pushedToNuget += 1
}
diff --git a/.github/workflows/External-Storage-Tests.yml b/.github/workflows/External-Storage-Tests.yml
index 5fae5df91..fbdafdbba 100644
--- a/.github/workflows/External-Storage-Tests.yml
+++ b/.github/workflows/External-Storage-Tests.yml
@@ -32,6 +32,12 @@ jobs:
uses: actions/setup-dotnet@v2
with:
dotnet-version: '6.0.x'
+
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
- name: Restore packages
run: dotnet restore $Env:SolutionFile
diff --git a/.github/workflows/call-beta-bot.yml b/.github/workflows/call-beta-bot.yml
new file mode 100644
index 000000000..d7cb4406e
--- /dev/null
+++ b/.github/workflows/call-beta-bot.yml
@@ -0,0 +1,18 @@
+name: Call Beta Bot
+
+on:
+ # Triggers the workflow on push to beta branch or changes in a pull request to main branch
+ push:
+ branches: [ "beta" ]
+ pull_request:
+ types: [ opened, synchronize, reopened, ready_for_review, closed, labeled, unlabeled ]
+ branches: [ "master" ]
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+jobs:
+ call-workflow:
+ if: github.repository_owner == 'genexuslabs'
+ uses: genexuslabs/build-genexus-reusable-workflow/.github/workflows/run-beta-bot.yml@main
+ secrets: inherit
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 000000000..70b0c49ec
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,91 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+# ******** NOTE ********
+
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master, beta*, release-* ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '28 9 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: windows-latest
+
+ env:
+ Configuration: Release
+ SolutionFile: dotnet\CodeqlSolution.sln
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+ # Learn more...
+ # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
+
+ steps:
+
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ debug: true
+ languages: ${{ matrix.language }}
+
+ - name: Install .NET 6
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '6.0.x'
+
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.0.100'
+
+ - name: Create temporary solution
+ run: |
+ $TempSolution = "CodeqlSolution"
+ dotnet new sln --name $TempSolution --output dotnet --force
+ dotnet msbuild dotnet\DotNetStandardClasses.sln /t:DumpProjects -p:DumpSolutionName=$TempSolution /m:1 -p:DumpSolutionTargetFrameworkDefault=net6
+
+ - name: Build temporary solution
+ run: dotnet build dotnet\CodeqlSolution.sln --framework net6.0
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ #- name: Autobuild
+ # uses: github/codeql-action/autobuild@v2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
+ with:
+ category: "/language:${{matrix.language}}"
\ No newline at end of file
diff --git a/.github/workflows/fortify-net-framework.yml b/.github/workflows/fortify-net-framework.yml
index 0c37aa982..8d4a1ce26 100644
--- a/.github/workflows/fortify-net-framework.yml
+++ b/.github/workflows/fortify-net-framework.yml
@@ -27,17 +27,22 @@ jobs:
with:
repository: ''
+ - name: Setup MSBuild
+ uses: microsoft/setup-msbuild@v1.1
+ with:
+ vs-prerelease: true
+
# Java 8 required by ScanCentral Client and FoD Uploader(Univeral CI Tool)
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 1.8
-
- - name: Setup MSBuild
- uses: microsoft/setup-msbuild@v1
+
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
with:
- vs-version: 10.0
-
+ dotnet-version: '8.0.100'
+
- name: Create temporal solution
run: |
$fortifysolution = "FortifySolution"
diff --git a/.github/workflows/fortify.yml b/.github/workflows/fortify.yml
index 4da890cd9..b2f08d3b8 100644
--- a/.github/workflows/fortify.yml
+++ b/.github/workflows/fortify.yml
@@ -27,17 +27,22 @@ jobs:
with:
repository: ''
+ - name: Setup MSBuild
+ uses: microsoft/setup-msbuild@v1.1
+ with:
+ vs-prerelease: true
+
# Java 8 required by ScanCentral Client and FoD Uploader(Univeral CI Tool)
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 1.8
-
- - name: Setup MSBuild
- uses: microsoft/setup-msbuild@v1
+
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
with:
- vs-version: 10.0
-
+ dotnet-version: '8.0.100'
+
- name: Create temporal solution
run: |
$fortifysolution = "FortifySolution"
diff --git a/.github/workflows/veracode.yml b/.github/workflows/veracode.yml
index 0f41536ad..b635e46b3 100644
--- a/.github/workflows/veracode.yml
+++ b/.github/workflows/veracode.yml
@@ -50,6 +50,11 @@ jobs:
dotnet-version: '6.0.x'
include-prerelease: false
+ - name: Install .NET 8
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '8.x'
+ include-prerelease: true
- name: Build
run: |
@@ -90,7 +95,7 @@ jobs:
pipeline-results-json: results.json
source-base-path-1: "^.*/${{ github.event.repository.name }}/dotnet/:dotnet/"
- - uses: github/codeql-action/upload-sarif@v1
+ - uses: github/codeql-action/upload-sarif@v2
with:
# Path to SARIF file relative to the root of the repository
sarif_file: veracode-results.sarif
diff --git a/README.md b/README.md
index 2b52c8372..6f4534743 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
# GeneXus Standard Classes for .NET and .NET Framework
GeneXus Standard Classes for .NET and .NET Framework generators.
-## Build status
-| Branch | Status
-|---|---
-|master|[![](https://github.com/genexuslabs/dotnetclasses/workflows/Build/badge.svg?branch=master)](https://github.com/genexuslabs/dotnetclasses/actions?query=workflow%3ABuild+branch%3Amaster)
-|beta|[![](https://github.com/genexuslabs/dotnetclasses/workflows/Build/badge.svg?branch=beta)](https://github.com/genexuslabs/dotnetclasses/actions?query=workflow%3ABuild+branch%3Abeta)
+## Repo status
+| Branch | Build | Security
+|---|---|---
+|master|[![](https://github.com/genexuslabs/dotnetclasses/workflows/Build/badge.svg?branch=master)](https://github.com/genexuslabs/dotnetclasses/actions?query=workflow%3ABuild+branch%3Amaster)|[![CodeQL](https://github.com/genexuslabs/DotNetClasses/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/genexuslabs/DotNetClasses/actions/workflows/codeql-analysis.yml)
+|beta|[![](https://github.com/genexuslabs/dotnetclasses/workflows/Build/badge.svg?branch=beta)](https://github.com/genexuslabs/dotnetclasses/actions?query=workflow%3ABuild+branch%3Abeta)|[![CodeQL](https://github.com/genexuslabs/DotNetClasses/actions/workflows/codeql-analysis.yml/badge.svg?branch=beta)](https://github.com/genexuslabs/DotNetClasses/actions/workflows/codeql-analysis.yml)
## Modules
@@ -66,8 +66,8 @@ This repository contains projects for .NET and .NET Framework. It is organized a
# How to build
## Requirements
-- Visual Studio 2022
-- .NET 6
+- Visual Studio 2022 (17.8 or higher).
+- .NET 6 & .NET 8
- .NET Framework 4.7 DevPack
# Instructions
diff --git a/dotnet/Directory.Build.props b/dotnet/Directory.Build.props
index 760d6f7c4..73083e09b 100644
--- a/dotnet/Directory.Build.props
+++ b/dotnet/Directory.Build.props
@@ -3,7 +3,7 @@
11.0.0.0
1
$([MSBuild]::Add($(MajorFileVersion), 100))
- 25
+ 31
$(COMMIT_NUMBER)
0
$(MajorFileVersion).$(MinorFileVersion).$(PatchFileVersion)
@@ -29,6 +29,8 @@
NU5105;CS0618;CS8032;CS0618;SYSLIB0021;SYSLIB0023
true
True
+
+ NU1900;NU1901;NU1902;NU1903;NU1904
diff --git a/dotnet/DotNetStandardClasses.sln b/dotnet/DotNetStandardClasses.sln
index 8650b334f..01e391f0b 100644
--- a/dotnet/DotNetStandardClasses.sln
+++ b/dotnet/DotNetStandardClasses.sln
@@ -243,6 +243,26 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GxOffice", "src\dotnetcore\
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "excel", "excel", "{B521FF6D-E081-4DE6-AC00-A9BE3B6439D1}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GXEventRouter", "src\dotnetcore\Providers\Messaging\GXEventRouter\GXEventRouter.csproj", "{5BBC75F0-E51A-4EBD-A628-92498D319B1D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GXAzureEventGrid", "src\dotnetcore\Providers\Messaging\GXAzureEventGrid\GXAzureEventGrid.csproj", "{7250CDB1-95C4-4822-B01B-3CBD73324CC9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCoreAttackMitigationTest", "test\DotNetCoreAttackMitigationTest\DotNetCoreAttackMitigationTest.csproj", "{2D615969-53E2-4B77-9A9A-75C33865CF76}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCoreChunkedTest", "test\DotNetCoreChunkedTest\DotNetCoreChunkedTest.csproj", "{5D2B1299-479F-430A-8D72-34D44FB299FD}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetPDFUnitTest", "test\DotNetPdfTest\DotNetPDFUnitTest.csproj", "{0FCFB078-5584-469F-92CC-61B0A6216D0D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GXOtel.Diagnostics", "src\dotnetcore\Providers\OpenTelemetry\Diagnostics\GXOtel.Diagnostics\GXOtel.Diagnostics.csproj", "{A42066E8-DDB9-4767-AEFA-E6D13EFF051A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCoreCmdTest", "test\DotNetCoreCmdTest\DotNetCoreCmdTest.csproj", "{956402BD-AC8C-426E-961B-B77B3F3EDAEB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{46DAAFD1-FAF5-4904-8EC5-406BE04E5538}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogTest", "test\benchmarks\LogTest\LogTest.csproj", "{A1DBDCE0-4F09-445F-A202-9B260CDD46CF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccessTokenController_Test", "test\NativeAccessControllerTest\AccessTokenController_Test.csproj", "{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -585,6 +605,42 @@ Global
{E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D615969-53E2-4B77-9A9A-75C33865CF76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D615969-53E2-4B77-9A9A-75C33865CF76}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D615969-53E2-4B77-9A9A-75C33865CF76}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D615969-53E2-4B77-9A9A-75C33865CF76}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5D2B1299-479F-430A-8D72-34D44FB299FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D2B1299-479F-430A-8D72-34D44FB299FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D2B1299-479F-430A-8D72-34D44FB299FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D2B1299-479F-430A-8D72-34D44FB299FD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0FCFB078-5584-469F-92CC-61B0A6216D0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0FCFB078-5584-469F-92CC-61B0A6216D0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0FCFB078-5584-469F-92CC-61B0A6216D0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0FCFB078-5584-469F-92CC-61B0A6216D0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A42066E8-DDB9-4767-AEFA-E6D13EFF051A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A42066E8-DDB9-4767-AEFA-E6D13EFF051A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A42066E8-DDB9-4767-AEFA-E6D13EFF051A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A42066E8-DDB9-4767-AEFA-E6D13EFF051A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {956402BD-AC8C-426E-961B-B77B3F3EDAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {956402BD-AC8C-426E-961B-B77B3F3EDAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {956402BD-AC8C-426E-961B-B77B3F3EDAEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {956402BD-AC8C-426E-961B-B77B3F3EDAEB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A1DBDCE0-4F09-445F-A202-9B260CDD46CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A1DBDCE0-4F09-445F-A202-9B260CDD46CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A1DBDCE0-4F09-445F-A202-9B260CDD46CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A1DBDCE0-4F09-445F-A202-9B260CDD46CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -701,6 +757,16 @@ Global
{BE108BE8-805D-4FCF-86BA-B2EAF581FFB2} = {F900A4AD-7249-41B4-B918-CB9E8C73747C}
{E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82} = {B521FF6D-E081-4DE6-AC00-A9BE3B6439D1}
{B521FF6D-E081-4DE6-AC00-A9BE3B6439D1} = {2261B65E-3757-4E5B-9DCD-EAE8D1E236A3}
+ {5BBC75F0-E51A-4EBD-A628-92498D319B1D} = {4C43F2DA-59E5-46F5-B691-195449498555}
+ {7250CDB1-95C4-4822-B01B-3CBD73324CC9} = {30159B0F-BE61-4DB7-AC02-02851426BE4B}
+ {2D615969-53E2-4B77-9A9A-75C33865CF76} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
+ {5D2B1299-479F-430A-8D72-34D44FB299FD} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
+ {0FCFB078-5584-469F-92CC-61B0A6216D0D} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
+ {A42066E8-DDB9-4767-AEFA-E6D13EFF051A} = {BBE020D4-C0FF-41A9-9EB1-D1EE12CC4BB8}
+ {956402BD-AC8C-426E-961B-B77B3F3EDAEB} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
+ {46DAAFD1-FAF5-4904-8EC5-406BE04E5538} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
+ {A1DBDCE0-4F09-445F-A202-9B260CDD46CF} = {46DAAFD1-FAF5-4904-8EC5-406BE04E5538}
+ {A5589382-DB6F-4450-AE2B-6C6AA1643EF1} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E18684C9-7D76-45CD-BF24-E3944B7F174C}
diff --git a/dotnet/src/dotnetcommon/DynService.Core/DynService.Core.csproj b/dotnet/src/dotnetcommon/DynService.Core/DynService.Core.csproj
index 6d8118577..45d27f4a7 100644
--- a/dotnet/src/dotnetcommon/DynService.Core/DynService.Core.csproj
+++ b/dotnet/src/dotnetcommon/DynService.Core/DynService.Core.csproj
@@ -1,6 +1,6 @@
- net462;net6.0
+ net462;net6.0;net8.0
GeneXus.Data.NTier
GeneXus.Data.DynService.Core
CA1812
@@ -18,4 +18,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/src/dotnetcommon/DynService.Dynamo/DynService.DynamoDB.csproj b/dotnet/src/dotnetcommon/DynService.Dynamo/DynService.DynamoDB.csproj
index 0cbb8aec8..16e8434b3 100644
--- a/dotnet/src/dotnetcommon/DynService.Dynamo/DynService.DynamoDB.csproj
+++ b/dotnet/src/dotnetcommon/DynService.Dynamo/DynService.DynamoDB.csproj
@@ -1,6 +1,6 @@
- net462;net6.0
+ net462;net6.0;net8.0
GeneXus.Data.NTier
GeneXus.Data.DynService.DynamoDB
false
@@ -13,6 +13,7 @@
+
diff --git a/dotnet/src/dotnetcommon/GxCryptography/EncryptionProvider.cs b/dotnet/src/dotnetcommon/GxCryptography/EncryptionProvider.cs
index c17a4064e..549cd8bcd 100644
--- a/dotnet/src/dotnetcommon/GxCryptography/EncryptionProvider.cs
+++ b/dotnet/src/dotnetcommon/GxCryptography/EncryptionProvider.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.IO;
@@ -58,7 +58,9 @@ public NativeSymmetricEncryption(string algorithm, int keySize)
_symAlg = Aes.Create();
break;
default:
+#pragma warning disable SYSLIB0045 // Type or member is obsolete
_symAlg = SymmetricAlgorithm.Create(algorithm);
+#pragma warning restore SYSLIB0045 // Type or member is obsolete
break;
}
if (_symAlg != null)
diff --git a/dotnet/src/dotnetcommon/GxCryptography/GxCryptography.csproj b/dotnet/src/dotnetcommon/GxCryptography/GxCryptography.csproj
index b5ffc6cc1..fef7ad094 100644
--- a/dotnet/src/dotnetcommon/GxCryptography/GxCryptography.csproj
+++ b/dotnet/src/dotnetcommon/GxCryptography/GxCryptography.csproj
@@ -1,8 +1,8 @@
- net462;net6.0
+ net462;net6.0;net8.0
GxCryptography
- 618;1607;1698;SYSLIB0021;SYSLIB0027;SYSLIB0028;SYSLIB0023
+ 618;1607;1698;SYSLIB0021;SYSLIB0027;SYSLIB0028;SYSLIB0023;SYSLIB0022
GxCryptography
Data Access
GeneXus.Cryptography
diff --git a/dotnet/src/dotnetcommon/GxCryptographyCommon/GxCryptographyCommon.csproj b/dotnet/src/dotnetcommon/GxCryptographyCommon/GxCryptographyCommon.csproj
index 4b040e8f1..d6db9c1ef 100644
--- a/dotnet/src/dotnetcommon/GxCryptographyCommon/GxCryptographyCommon.csproj
+++ b/dotnet/src/dotnetcommon/GxCryptographyCommon/GxCryptographyCommon.csproj
@@ -1,6 +1,6 @@
- net462;net6.0
+ net462;net6.0;net8.0
GxCryptographyCommon
618;1607;1698
GxCryptographyCommon
diff --git a/dotnet/src/dotnetcommon/GxEncrypt/GxEncrypt.csproj b/dotnet/src/dotnetcommon/GxEncrypt/GxEncrypt.csproj
index a46827308..080986242 100644
--- a/dotnet/src/dotnetcommon/GxEncrypt/GxEncrypt.csproj
+++ b/dotnet/src/dotnetcommon/GxEncrypt/GxEncrypt.csproj
@@ -1,12 +1,16 @@
- net462;net6.0
+ net462;net6.0;net8.0
GeneXus.Encryption
GxEncrypt
Encrypt64 Decrypt64
GeneXus.Encrypt
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBConnection.cs b/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBConnection.cs
index 34bf4cea4..2d64302a9 100644
--- a/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBConnection.cs
+++ b/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBConnection.cs
@@ -12,7 +12,6 @@
using GeneXus.Cache;
using GeneXus.Data.Cosmos;
using GeneXus.Data.NTier.CosmosDB;
-using log4net;
using Microsoft.Azure.Cosmos;
namespace GeneXus.Data.NTier
@@ -25,6 +24,24 @@ public override IDataReader GetCacheDataReader(CacheItem item, bool computeSize,
{
return new GxCosmosDBCacheDataReader(item, computeSize, keyCache);
}
+ protected override string BuildConnectionStringForLog(string datasourceName, string userId,
+ string userPassword, string databaseName, string port, string schema, string extra)
+ {
+ StringBuilder connectionString = new StringBuilder();
+ if (!string.IsNullOrEmpty(datasourceName))
+ {
+ connectionString.AppendFormat("Data Source={0};", NaV);
+ }
+ if (userId != null)
+ {
+ connectionString.AppendFormat(";User ID={0};Password={1}", userId, NaV);
+ }
+ if (!string.IsNullOrEmpty(extra))
+ {
+ connectionString.AppendFormat(";{0}", extra);
+ }
+ return connectionString.ToString();
+ }
}
public class CosmosDBConnection : ServiceConnection
@@ -47,7 +64,7 @@ public class CosmosDBConnection : ServiceConnection
//Options not supported by the spec yet
//private const string DISTINCT = "DISTINCT";
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(CosmosDBConnection));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
public override string ConnectionString
{
get
diff --git a/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBDataReader.cs b/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBDataReader.cs
index f74528139..45ee1b70a 100644
--- a/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBDataReader.cs
+++ b/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBDataReader.cs
@@ -9,7 +9,6 @@
using GeneXus.Cache;
using GeneXus.Data.NTier;
using GeneXus.Data.NTier.CosmosDB;
-using log4net;
using Microsoft.Azure.Cosmos;
using Newtonsoft.Json;
@@ -27,7 +26,7 @@ public class CosmosDBDataReader : IDataReader
private int ItemCount;
private List> Items = null;
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(CosmosDBDataReader));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
private void CheckCurrentPosition()
{
if (m_currentEntry == null)
diff --git a/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBRequestWrapper.cs b/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBRequestWrapper.cs
index aaa3a62c2..faf6b9f97 100644
--- a/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBRequestWrapper.cs
+++ b/dotnet/src/dotnetcore/DynService/Cosmos/CosmosDBRequestWrapper.cs
@@ -3,7 +3,6 @@
using System.IO;
using System.Threading.Tasks;
using GeneXus.Data.Cosmos;
-using log4net;
using Microsoft.Azure.Cosmos;
using Newtonsoft.Json;
@@ -14,7 +13,7 @@ public class RequestWrapper
private readonly Container m_container;
private readonly CosmosClient m_cosmosClient;
private readonly QueryDefinition m_queryDefinition;
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(RequestWrapper));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
public string idValue { get; set; }
public object partitionKeyValue { get; set; }
public bool queryByPK { get; set; }
diff --git a/dotnet/src/dotnetcore/DynService/Cosmos/DynService.CosmosDB.csproj b/dotnet/src/dotnetcore/DynService/Cosmos/DynService.CosmosDB.csproj
index 120fad8f9..0c61c7593 100644
--- a/dotnet/src/dotnetcore/DynService/Cosmos/DynService.CosmosDB.csproj
+++ b/dotnet/src/dotnetcore/DynService/Cosmos/DynService.CosmosDB.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
GeneXus.Data.NTier
GeneXus.Data.DynService.CosmosDB
false
@@ -13,7 +13,9 @@
-
+
+
+
diff --git a/dotnet/src/dotnetcore/DynService/OData/DynServiceOData.csproj b/dotnet/src/dotnetcore/DynService/OData/DynServiceOData.csproj
index 6626d65c7..d57e3d3ee 100644
--- a/dotnet/src/dotnetcore/DynService/OData/DynServiceOData.csproj
+++ b/dotnet/src/dotnetcore/DynService/OData/DynServiceOData.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
NETCORE
DynService OData
GeneXus.DynService.OData.Core
@@ -12,8 +12,8 @@
+
-
diff --git a/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj b/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj
index 5d7ca697c..e95fc82c8 100644
--- a/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj
+++ b/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
NETCORE;
GXGeolocation GXHttpServices WebSocket
GeneXus.Classes.Web.Core
@@ -29,7 +29,9 @@
-
+
+
+
@@ -43,11 +45,5 @@
-
-
- False
- ..\libs\Jayrock.dll
-
-
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXBCRestService.cs b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXBCRestService.cs
index 4b603f65b..e93c59ac1 100644
--- a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXBCRestService.cs
+++ b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXBCRestService.cs
@@ -43,10 +43,10 @@ public override Task Post()
bool gxinsertorupdate = IsRestParameter(INSERT_OR_UPDATE_PARAMETER);
GxSilentTrnSdt entity = (GxSilentTrnSdt)Activator.CreateInstance(_worker.GetType(), new Object[] { _gxContext });
- var entity_interface = MakeRestType(entity, false);
+ object entity_interface = MakeRestType(entity, false);
entity_interface = ReadRequestBodySDTObj(entity_interface.GetType());
- var worker_interface = MakeRestType(_worker, false);
+ object worker_interface = MakeRestType(_worker, false);
worker_interface.GetType().GetMethod("CopyFrom").Invoke(worker_interface, new object[] { entity_interface });
if (gxcheck)
@@ -191,12 +191,12 @@ public override Task Put(object parameters)
{
bool gxcheck = IsRestParameter(CHECK_PARAMETER);
GxSilentTrnSdt entity = (GxSilentTrnSdt)Activator.CreateInstance(_worker.GetType(), new Object[] { _gxContext });
- var entity_interface = MakeRestType(entity, false);
+ object entity_interface = MakeRestType(entity, false);
entity_interface = ReadRequestBodySDTObj(entity_interface.GetType());
string entityHash = entity_interface.GetType().GetProperty("Hash").GetValue(entity_interface) as string;
ReflectionHelper.CallBCMethod(_worker, LOAD_METHOD, key);
- var worker_interface = MakeRestType(_worker, false);
+ object worker_interface = MakeRestType(_worker, false);
string currentHash = worker_interface.GetType().GetProperty("Hash").GetValue(worker_interface) as string;
if (entityHash == currentHash)
{
@@ -249,7 +249,7 @@ private object ReadRequestBodySDTObj(Type type)
{
using (var reader = new StreamReader(_httpContext.Request.Body))
{
- var sdtData = reader.ReadToEnd();
+ string sdtData = reader.ReadToEnd();
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(sdtData)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(type);
diff --git a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs
index 25573f464..5851c9081 100644
--- a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs
+++ b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs
@@ -15,20 +15,17 @@
using GeneXus.Http;
using GeneXus.HttpHandlerFactory;
using GeneXus.Metadata;
-using GeneXus.Procedure;
using GeneXus.Utils;
-using log4net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Net.Http.Headers;
namespace GxClasses.Web.Middleware
{
internal class GXRouting : IGXRouting
{
- static readonly ILog log = log4net.LogManager.GetLogger(typeof(IGXRouting));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
public static string VirtualPath = string.Empty;
public static string LocalPath = Directory.GetCurrentDirectory();
@@ -47,7 +44,7 @@ internal class GXRouting : IGXRouting
static Regex SDSVC_PATTERN = new Regex("([^/]+/)*(sdsvc_[^/]+/[^/]+)(\\?.*)*");
- const string PRIVATE_DIR = "private";
+ internal const string PRIVATE_DIR = "private";
public Dictionary servicesPathUrl = new Dictionary();
public Dictionary> servicesMap = new Dictionary>();
public Dictionary, String>> servicesMapData = new Dictionary, string>>();
@@ -61,6 +58,7 @@ public GXRouting(string baseURL)
ServicesGroupSetting();
ServicesFunctionsMetadata();
GetAzureDeploy();
+ SvcFiles();
}
static public List GetRouteController(Dictionary apiPaths,
@@ -353,19 +351,53 @@ internal string GetGxRouteValue(string path)
}
public bool ServiceInPath(String path, out String actualPath)
{
- actualPath = string.Empty;
- foreach (String subPath in servicesPathUrl.Keys)
+ actualPath = null;
+ string tmppath = path.Substring(0, 1).Equals("/") ? path.Substring(1) : path;
+ int pos = tmppath.IndexOf("/");
+ if (pos > 0)
{
- if (path.ToLower().Contains($"/{subPath.ToLower()}"))
+ string innerPath = tmppath.Substring(pos, tmppath.Length - pos);
+ actualPath = FindPath(innerPath, servicesPathUrl, true);
+ }
+ if (String.IsNullOrEmpty(actualPath))
+ {
+ // fallback
+ actualPath = FindPath(path, servicesPathUrl, false);
+ if (String.IsNullOrEmpty(actualPath))
+ {
+ actualPath = String.Empty;
+ GXLogging.Debug(log, $"ServiceInPath path:{path} not found");
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else {
+ return true;
+ }
+ }
+
+ private String FindPath(string innerPath, Dictionary servicesPathUrl, bool startTxt)
+ {
+ string actualPath = String.Empty;
+ foreach (var subPath in from String subPath in servicesPathUrl.Keys
+ select subPath)
+ {
+ bool match = false;
+ innerPath = innerPath.ToLower();
+ match = (startTxt)? innerPath.StartsWith($"/{subPath.ToLower()}"): innerPath.Contains($"/{subPath.ToLower()}");
+ if (match)
{
actualPath = subPath.ToLower();
GXLogging.Debug(log, $"ServiceInPath actualPath:{actualPath}");
- return true;
+ return subPath;
}
}
- GXLogging.Debug(log, $"ServiceInPath path:{path} not found");
- return false;
+ return null;
}
+
public GxRestWrapper GetController(HttpContext context, string controller, string methodName, Dictionary variableAlias)
{
return GetController(context, new ControllerInfo() { Name = controller, MethodName = methodName, VariableAlias = variableAlias });
@@ -380,8 +412,7 @@ public GxRestWrapper GetController(HttpContext context, ControllerInfo controlle
GxContext gxContext = GxContext.CreateDefaultInstance();
gxContext.HttpContext = context;
context.NewSessionCheck();
- string nspace;
- Config.GetValueOf("AppMainNamespace", out nspace);
+ string nspace = Preferences.AppMainNamespace;
String tmpController = controller;
String addNspace = string.Empty;
@@ -400,7 +431,7 @@ public GxRestWrapper GetController(HttpContext context, ControllerInfo controlle
bool privateDirExists = Directory.Exists(privateDir);
GXLogging.Debug(log, $"PrivateDir:{privateDir} asssemblycontroller:{asssemblycontroller}");
-
+ string svcFile=null;
if (privateDirExists && File.Exists(Path.Combine(privateDir, $"{asssemblycontroller.ToLower()}.grp.json")))
{
controller = tmpController;
@@ -415,9 +446,7 @@ public GxRestWrapper GetController(HttpContext context, ControllerInfo controlle
else
{
string controllerLower = controller.ToLower();
- string svcFile = SvcFile($"{controller}{SvcExtension}");
- if (svcFile==null)
- svcFile = SvcFile($"{controllerLower}{SvcExtension}");
+ svcFile = SvcFile($"{controller}{SvcExtension}");
if (File.Exists(svcFile))
{
string[] controllerAssemblyQualifiedName = new string(File.ReadLines(svcFile).First().SkipWhile(c => c != '"')
@@ -449,22 +478,26 @@ public GxRestWrapper GetController(HttpContext context, ControllerInfo controlle
GXLogging.Warn(log, $"Controller was not found");
return null;
}
- string SvcFile(string controller)
+
+ private void SvcFiles()
{
- if (svcFiles == null)
+ svcFiles = new HashSet(new CaseInsensitiveStringEqualityComparer());
+ foreach (string file in Directory.GetFiles(ContentRootPath, SvcExtensionPattern, SearchOption.AllDirectories))
{
- svcFiles = new HashSet();
- foreach (string file in Directory.GetFiles(ContentRootPath, SvcExtensionPattern, SearchOption.AllDirectories))
- {
- svcFiles.Add(file);
- }
+ svcFiles.Add(file);
}
+ }
+ string SvcFile(string controller)
+ {
string fileName;
- string controllerFullName = Path.Combine(ContentRootPath, controller);
- if (svcFiles.TryGetValue(new FileInfo(controllerFullName).FullName, out fileName))
+ string controllerFullName = new FileInfo(Path.Combine(ContentRootPath, controller)).FullName;
+ if (svcFiles.TryGetValue(controllerFullName, out fileName))
return fileName;
else
+ {
+ GXLogging.Warn(log, "Service file not found:" + controllerFullName);
return null;
+ }
}
public void ServicesGroupSetting()
@@ -604,7 +637,18 @@ public string GAM
}
+ internal class CaseInsensitiveStringEqualityComparer : IEqualityComparer
+ {
+ public bool Equals(string x, string y)
+ {
+ return string.Equals(x, y, StringComparison.OrdinalIgnoreCase);
+ }
+ public int GetHashCode(string obj)
+ {
+ return obj.ToLower().GetHashCode();
+ }
+ }
public static class AzureFeature
{
public const string AzureServerless = "AzureServerless";
diff --git a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/HandlerFactory.cs b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/HandlerFactory.cs
index 549b6ba9e..d072c5d27 100644
--- a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/HandlerFactory.cs
+++ b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/HandlerFactory.cs
@@ -1,17 +1,16 @@
using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
using System.Reflection;
+using System.Threading.Tasks;
+using GeneXus.Application;
using GeneXus.Configuration;
-using log4net;
+using GeneXus.Http;
+using GeneXus.Mime;
+using GeneXus.Procedure;
using GeneXus.Utils;
using Microsoft.AspNetCore.Http;
-using System.Threading.Tasks;
-using Microsoft.Extensions.Options;
-using System.Net;
-using GeneXus.Mime;
-using GeneXus.Http;
-using System.Collections.Generic;
-using GeneXus.Application;
-using System.IO;
namespace GeneXus.HttpHandlerFactory
{
@@ -32,32 +31,13 @@ public class BaseUrls
public class HandlerFactory
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.HttpHandlerFactory.HandlerFactory));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
private string _basePath;
static Dictionary _aspxObjects = new Dictionary(){
{"gxoauthlogout",typeof(GXOAuthLogout)},
{"gxoauthuserinfo",typeof(GXOAuthUserInfo)},
{"gxoauthaccesstoken",typeof(GXOAuthAccessToken)},
{"gxmulticall",typeof(GXMultiCall)}};
- static Dictionary _aspxRewrite = new Dictionary(){
- {"oauth/access_token","gxoauthaccesstoken.aspx"},
- {"oauth/logout","gxoauthlogout.aspx"},
- {"oauth/userinfo","gxoauthuserinfo.aspx"},
- {"oauth/gam/signin","agamextauthinput.aspx"},
- {"oauth/gam/callback","agamextauthinput.aspx"},
- {"oauth/gam/access_token","agamoauth20getaccesstoken.aspx"},
- {"oauth/gam/userinfo","agamoauth20getuserinfo.aspx"},
- {"oauth/gam/signout","agamextauthinput.aspx"},
- {"saml/gam/signin","Saml2/SignIn"},
- {"saml/gam/callback","gamexternalauthenticationinputsaml20_ws.aspx"},
- {"saml/gam/signout","Saml2/Logout"},
- {"oauth/requesttokenservice","agamstsauthappgetaccesstoken.aspx"},
- {"oauth/queryaccesstoken","agamstsauthappvalidaccesstoken.aspx"},
- {"oauth/gam/v2.0/access_token","agamoauth20getaccesstoken_v20.aspx"},
- {"oauth/gam/v2.0/userinfo","agamoauth20getuserinfo_v20.aspx"},
- {"oauth/gam/v2.0/requesttokenanduserinfo","aGAMSSORestRequestTokenAndUserInfo_v20.aspx"}};
- private const string QUERYVIEWER_NAMESPACE = "QueryViewer.Services";
- private const string GXFLOW_NSPACE = "GXflow.Programs";
private static List GxNamespaces;
public HandlerFactory()
@@ -95,8 +75,16 @@ public async Task Invoke(HttpContext context)
handler.sendAdditionalHeaders();
return Task.CompletedTask;
});
- handler.ProcessRequest(context);
- await Task.CompletedTask;
+ GXWebProcedure gxWebProc = handler as GXWebProcedure;
+ if (gxWebProc != null && gxWebProc.GetAsyncEnabledInternal())
+ {
+ await gxWebProc.ProcessRequestAsync(context);
+ }
+ else
+ {
+ handler.ProcessRequest(context);
+ await Task.CompletedTask;
+ }
handler.ControlOutputWriter?.Flush();
}
else
@@ -124,9 +112,9 @@ private static string ObjectUrl(string requestPath, string basePath)
}
lastSegment = CleanUploadUrlSuffix(lastSegment.TrimStart('/').ToLower());
GXLogging.Debug(log, "ObjectUrl:", lastSegment);
- if (_aspxRewrite.ContainsKey(lastSegment))
+ if (HttpHelper.GAMServices.ContainsKey(lastSegment))
{
- return _aspxRewrite[lastSegment];
+ return HttpHelper.GAMServices[lastSegment];
}
return lastSegment;
}
@@ -169,11 +157,15 @@ public IHttpHandler GetHandler(HttpContext context, string requestType, string u
string className;
if (cname.StartsWith("agxpl_", StringComparison.OrdinalIgnoreCase) || cname.Equals("gxqueryviewerforsd", StringComparison.OrdinalIgnoreCase))
{
- className = $"{QUERYVIEWER_NAMESPACE}.{cname}";
+ className = $"{HttpHelper.QUERYVIEWER_NAMESPACE}.{cname}";
}
else if (Preferences.GxpmEnabled && (cname.StartsWith("awf", StringComparison.OrdinalIgnoreCase) || cname.StartsWith("wf", StringComparison.OrdinalIgnoreCase) || cname.StartsWith("apwf", StringComparison.OrdinalIgnoreCase)))
{
- className = $"{GXFLOW_NSPACE}.{cname}";
+ className = $"{HttpHelper.GXFLOW_NSPACE}.{cname}";
+ }
+ else if (HttpHelper.GamServicesInternalName.Contains(cname))
+ {
+ className = $"{HttpHelper.GAM_NSPACE}.{cname}";
}
else
{
diff --git a/dotnet/src/dotnetcore/GxClasses.Web/Notifications/WebSocket/WSHandler.cs b/dotnet/src/dotnetcore/GxClasses.Web/Notifications/WebSocket/WSHandler.cs
index ae0051f63..84430c30a 100644
--- a/dotnet/src/dotnetcore/GxClasses.Web/Notifications/WebSocket/WSHandler.cs
+++ b/dotnet/src/dotnetcore/GxClasses.Web/Notifications/WebSocket/WSHandler.cs
@@ -1,11 +1,8 @@
-using GeneXus.Configuration;
-using GeneXus.Metadata;
-using GeneXus.Notifications.WebSocket;
-using GeneXus.Procedure;
-using GeneXus.Services;
-using GeneXus.Utils;
+#if NETCORE
+using GeneXus.Application;
+#else
using Jayrock.Json;
-using log4net;
+#endif
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,12 +10,18 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using GeneXus.Configuration;
+using GeneXus.Metadata;
+using GeneXus.Notifications.WebSocket;
+using GeneXus.Procedure;
+using GeneXus.Services;
+using GeneXus.Utils;
namespace GeneXus.Http.WebSocket
{
public class WSHandler: WebSocketHandler, IGXWebSocketAsync
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(WSHandler));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
private const string GX_NOTIFICATIONINFO_NAME = "GeneXus.Core.genexus.server.SdtNotificationInfo";
protected static WebSocketConnectionManager WebSocketConnectionManager = new WebSocketConnectionManager();
@@ -120,8 +123,7 @@ private bool ExecuteHandler(HandlerType type, Object[] parameters)
{
try
{
- string nSpace = string.Empty;
- Config.GetValueOf("AppMainNamespace", out nSpace);
+ string nSpace = Preferences.AppMainNamespace;
GXProcedure obj = null;
try
{
diff --git a/dotnet/src/dotnetcore/GxClasses.Web/Properties/AssemblyInfo.cs b/dotnet/src/dotnetcore/GxClasses.Web/Properties/AssemblyInfo.cs
index 7138fabec..c6a284870 100644
--- a/dotnet/src/dotnetcore/GxClasses.Web/Properties/AssemblyInfo.cs
+++ b/dotnet/src/dotnetcore/GxClasses.Web/Properties/AssemblyInfo.cs
@@ -5,4 +5,6 @@
[assembly: InternalsVisibleTo("DotNetCoreWebUnitTest")]
[assembly: InternalsVisibleTo("GxNetCoreStartup")]
[assembly: InternalsVisibleTo("GeneXus.Deploy.AzureFunctions.Handlers")]
-[assembly: InternalsVisibleTo("AzureFunctionsTest")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("AzureFunctionsTest")]
+[assembly: InternalsVisibleTo("DotNetCoreAttackMitigationTest")]
+[assembly: InternalsVisibleTo("DotNetCoreChunkedTest")]
diff --git a/dotnet/src/dotnetcore/GxClasses/Domain/GXXmlReadWrite.cs b/dotnet/src/dotnetcore/GxClasses/Domain/GXXmlReadWrite.cs
index 369c75818..2c5fe2630 100644
--- a/dotnet/src/dotnetcore/GxClasses/Domain/GXXmlReadWrite.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Domain/GXXmlReadWrite.cs
@@ -1,19 +1,17 @@
using System;
-using System.Xml;
using System.Collections;
using System.Collections.Specialized;
-using System.Text;
-using System.Net;
using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
using System.Xml.Schema;
+using System.Xml.XPath;
+using System.Xml.Xsl;
using GeneXus.Application;
using GeneXus.Http.Client;
using GeneXus.Http.Server;
using GeneXus.Utils;
-using log4net;
-
-using System.Xml.Xsl;
-using System.Xml.XPath;
namespace GeneXus.XML
{
@@ -32,7 +30,6 @@ public interface IGxXmlFunctions
}
public class GXXMLReader : IDisposable
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.Configuration.Config));
public const short ElementType = 1;
public const short EndTagType = 2;
public const short TextType = 4;
@@ -275,14 +272,6 @@ public void OpenFromString(string s)
Uri baseUri = new Uri( sBaseDirectory );
Resolver.Myself = baseUri;
CreateXMLSettings();
- try
- {
- if (File.Exists(s))
- XMLInput = new FileStream(s, FileMode.Open, FileAccess.Read);
- }
- catch(Exception ex) {
- GXLogging.Warn(log, "OpenFromString file failed", ex);
- }
if (XMLInput ==null)
XMLInput = new StringReader(s);
}
@@ -1143,7 +1132,7 @@ internal void AppendNode(GXSOAPContext ctx, Node node, int extent)
char[] trimChars = { '\t', ' ' };
- if (node.NodeType != ElementType) return;
+ if (node==null || node.NodeType != ElementType) return;
switch (node.NodeType)
{
case ElementType:
@@ -1896,7 +1885,7 @@ public void Dispose()
public class GXXMLWriter: IDisposable
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GXXMLWriter));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
private XmlTextWriter writer;
private short errorCode;
@@ -2142,6 +2131,10 @@ string removeUnallowedChars( string s)
public short WriteElement (string Name, string Value)
{
WriteStartElement(Name);
+ if (Value==null)
+ {
+ Value = string.Empty;
+ }
valueBuffer = Value;
return 0;
}
diff --git a/dotnet/src/dotnetcore/GxClasses/Domain/JArray.cs b/dotnet/src/dotnetcore/GxClasses/Domain/JArray.cs
new file mode 100644
index 000000000..8d53a77e4
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxClasses/Domain/JArray.cs
@@ -0,0 +1,360 @@
+#region License, Terms and Conditions
+//
+// Jayrock - A JSON-RPC implementation for the Microsoft .NET Framework
+// Written by Atif Aziz (atif.aziz@skybow.com)
+// Copyright (c) Atif Aziz. All rights reserved.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 2.1 of the License, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+#endregion
+
+namespace GeneXus.Application
+{
+ #region Imports
+
+ using System;
+ using System.Collections;
+ using System.Globalization;
+ using System.Text;
+ using GeneXus.Utils;
+
+ #endregion
+
+ ///
+ /// An ordered sequence of values. This class also provides a number of
+ /// methods that can be found on a JavaScript Array for sake of parity.
+ ///
+ ///
+ ///
+ /// Public Domain 2002 JSON.org, ported to C# by Are Bjolseth (teleplan.no)
+ /// and re-adapted by Atif Aziz (www.raboof.com)
+ ///
+
+ [ Serializable ]
+ internal class JArray : CollectionBase, IJayrockCompatible
+ {
+ public JArray() {}
+
+ public JArray(IEnumerable collection)
+ {
+ foreach (object item in collection)
+ List.Add(item);
+ }
+
+ public virtual object this[int index]
+ {
+ get { return InnerList[index]; }
+ set { List[index] = value; }
+ }
+
+ public int Length
+ {
+ get { return Count; }
+ }
+
+ public JArray Put(object value)
+ {
+ Add(value);
+ return this;
+ }
+
+ public virtual void Add(object value)
+ {
+ List.Add(value);
+ }
+ public virtual void Add(int index, object value)
+ {
+ InnerList.Insert(index, value);
+ }
+
+ public virtual void Remove(object value)
+ {
+ List.Remove(value);
+ }
+
+ public virtual bool Contains(object value)
+ {
+ return List.Contains(value);
+ }
+
+ public virtual int IndexOf(object value)
+ {
+ return List.IndexOf(value);
+ }
+
+ public virtual bool HasValueAt(int index)
+ {
+ return this[index] != null;
+ }
+
+ public virtual object GetValue(int index)
+ {
+ return GetValue(index, null);
+ }
+
+ public virtual object GetValue(int index, object defaultValue)
+ {
+ object value = this[index];
+ return value != null ? value : defaultValue;
+ }
+
+ public virtual bool GetBoolean(int index)
+ {
+ return GetBoolean(index, false);
+ }
+
+ public virtual bool GetBoolean(int index, bool defaultValue)
+ {
+ object value = GetValue(index);
+ if (value == null) return defaultValue;
+ return Convert.ToBoolean(value, CultureInfo.InvariantCulture);
+ }
+
+ public virtual double GetDouble(int index)
+ {
+ return GetDouble(index, float.NaN);
+ }
+
+ public virtual double GetDouble(int index, float defaultValue)
+ {
+ object value = GetValue(index);
+ if (value == null) return defaultValue;
+ return Convert.ToDouble(value, CultureInfo.InvariantCulture);
+ }
+
+ public virtual int GetInt32(int index)
+ {
+ return GetInt32(index, 0);
+ }
+
+ public virtual int GetInt32(int index, int defaultValue)
+ {
+ object value = GetValue(index);
+ if (value == null) return defaultValue;
+ return Convert.ToInt32(value, CultureInfo.InvariantCulture);
+ }
+
+ public virtual string GetString(int index)
+ {
+ return GetString(index, string.Empty);
+ }
+
+ public virtual string GetString(int index, string defaultValue)
+ {
+ object value = GetValue(index);
+ if (value == null) return defaultValue;
+ return value.ToString();
+ }
+
+ public virtual JArray GetArray(int index)
+ {
+ return (JArray) GetValue(index);
+ }
+
+ public virtual JObject GetObject(int index)
+ {
+ return (JObject) GetValue(index);
+ }
+
+ protected override void OnValidate(object value)
+ {
+ //
+ // Null values are allowed in a JSON array so don't delegate
+ // to the base class (CollectionBase) implementation since that
+ // disallows null entries by default.
+ //
+ }
+
+ ///
+ /// Make an JSON external form string of this JsonArray. For
+ /// compactness, no unnecessary whitespace is added.
+ ///
+ ///
+ /// This method assumes that the data structure is acyclical.
+ ///
+
+ public override string ToString()
+ {
+ return TextJsonSerializer.SerializeToJayrockCompatibleJson(this);
+ }
+
+
+ ///
+ /// Copies the elements to a new object array.
+ ///
+
+ public virtual object[] ToArray()
+ {
+ return (object[]) ToArray(typeof(object));
+ }
+
+ ///
+ /// Copies the elements to a new array of the specified type.
+ ///
+
+ public virtual Array ToArray(Type elementType)
+ {
+ return InnerList.ToArray(elementType);
+ }
+
+ public virtual void Reverse()
+ {
+ InnerList.Reverse();
+ }
+
+ //
+ // Methods that imitate the JavaScript array methods.
+ //
+
+ ///
+ /// Appends new elements to an array.
+ ///
+ ///
+ /// The new length of the array.
+ ///
+ ///
+ /// This method appends elements in the order in which they appear. If
+ /// one of the arguments is an array, it is added as a single element.
+ /// Use the method to join the elements from two or
+ /// more arrays.
+ ///
+
+ public int Push(object value)
+ {
+ Add(value);
+ return Count;
+ }
+
+ ///
+ /// Appends new elements to an array.
+ ///
+ ///
+ /// The new length of the array.
+ ///
+ ///
+ /// This method appends elements in the order in which they appear. If
+ /// one of the arguments is an array, it is added as a single element.
+ /// Use the method to join the elements from two or
+ /// more arrays.
+ ///
+
+ public int Push(params object[] values)
+ {
+ if (values != null)
+ {
+ foreach (object value in values)
+ Push(value);
+ }
+
+ return Count;
+ }
+
+ ///
+ /// Removes the last element from an array and returns it.
+ ///
+ ///
+ /// If the array is empty, null is returned.
+ ///
+
+ public object Pop()
+ {
+ if (Count == 0)
+ return null;
+
+ object lastValue = InnerList[Count - 1];
+ RemoveAt(Count - 1);
+ return lastValue;
+ }
+
+ ///
+ /// Returns a new array consisting of a combination of two or more
+ /// arrays.
+ ///
+
+ public JArray Concat(params object[] values)
+ {
+ JArray newArray = new JArray(this);
+
+ if (values != null)
+ {
+ foreach (object value in values)
+ {
+ JArray arrayValue = value as JArray;
+
+ if (arrayValue != null)
+ {
+ foreach (object arrayValueValue in arrayValue)
+ newArray.Push(arrayValueValue);
+ }
+ else
+ {
+ newArray.Push(value);
+ }
+ }
+ }
+
+ return newArray;
+ }
+
+ ///
+ /// Removes the first element from an array and returns it.
+ ///
+
+ public object Shift()
+ {
+ if (Count == 0)
+ return null;
+
+ object firstValue = InnerList[0];
+ RemoveAt(0);
+ return firstValue;
+ }
+
+ ///
+ /// Returns an array with specified elements inserted at the beginning.
+ ///
+ ///
+ /// The unshift method inserts elements into the start of an array, so
+ /// they appear in the same order in which they appear in the argument
+ /// list.
+ ///
+
+ public JArray Unshift(object value)
+ {
+ List.Insert(0, value);
+ return this;
+ }
+
+ ///
+ /// Returns an array with specified elements inserted at the beginning.
+ ///
+ ///
+ /// The unshift method inserts elements into the start of an array, so
+ /// they appear in the same order in which they appear in the argument
+ /// list.
+ ///
+
+ public JArray Unshift(params object[] values)
+ {
+ if (values != null)
+ {
+ foreach (object value in values)
+ Unshift(value);
+ }
+
+ return this;
+ }
+ }
+}
diff --git a/dotnet/src/dotnetcore/GxClasses/Domain/JNull.cs b/dotnet/src/dotnetcore/GxClasses/Domain/JNull.cs
new file mode 100644
index 000000000..434ad643d
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxClasses/Domain/JNull.cs
@@ -0,0 +1,87 @@
+#region License, Terms and Conditions
+//
+// Jayrock - A JSON-RPC implementation for the Microsoft .NET Framework
+// Written by Atif Aziz (atif.aziz@skybow.com)
+// Copyright (c) Atif Aziz. All rights reserved.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 2.1 of the License, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+#endregion
+
+namespace GeneXus.Application
+{
+ #region Imports
+
+ using System;
+ //using System.Data.SqlTypes;
+ #endregion
+
+ ///
+ /// Represent the one and only representation of the "null" value in JSON.
+ ///
+
+ internal interface IJayrockCompatible
+ {
+
+ }
+ [ Serializable ]
+ internal sealed class JNull : IJayrockCompatible
+ {
+ public static readonly JNull Value = new JNull();
+
+ public override string ToString()
+ {
+ return "null";
+ }
+
+ public static bool LogicallyEquals(object o)
+ {
+ //
+ // Equals a null reference.
+ //
+
+ if (o == null)
+ return true;
+
+ //
+ // Equals self, of course.
+ //
+
+ if (o.Equals(JNull.Value))
+ return true;
+
+ //
+ // Equals the logical null value used in database applications.
+ //
+
+ //if (Convert.IsDBNull(o))
+ // return true;
+
+ //
+ // Equals any type that supports logical nullability and whose
+ // current state is logically null.
+ //
+
+ //INullable nullable = o as INullable;
+
+ // if (nullable == null)
+ return false;
+
+ //return nullable.IsNull;
+ }
+
+ private JNull() {}
+ }
+}
diff --git a/dotnet/src/dotnetcore/GxClasses/Domain/JObject.cs b/dotnet/src/dotnetcore/GxClasses/Domain/JObject.cs
new file mode 100644
index 000000000..e1aadfc30
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxClasses/Domain/JObject.cs
@@ -0,0 +1,123 @@
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 2.1 of the License, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using GeneXus.Utils;
+namespace GeneXus.Application
+{
+ /// the implementation does internally try to remember the order in which
+ /// the keys were added in order facilitate human-readability as in when
+ /// an instance is rendered as text.
+
+ [ Serializable ]
+ internal class JObject : OrderedDictionary, IJayrockCompatible
+ {
+ public JObject() {}
+
+ ///
+ /// Construct a JObject from a IDictionary
+ ///
+
+ public JObject(IDictionary members)
+ {
+ foreach (DictionaryEntry entry in members)
+ {
+ if (entry.Key == null)
+ throw new Exception("InvalidMemberException");
+
+ base.Add(entry.Key.ToString(), entry.Value);
+ }
+
+ }
+
+ public virtual bool HasMembers
+ {
+ get { return Count > 0; }
+ }
+
+
+ ///
+ /// Accumulate values under a key. It is similar to the Put method except
+ /// that if there is already an object stored under the key then a
+ /// JArray is stored under the key to hold all of the accumulated values.
+ /// If there is already a JArray, then the new value is appended to it.
+ /// In contrast, the Put method replaces the previous value.
+ ///
+
+ public virtual JObject Accumulate(string name, object value)
+ {
+ if (name == null)
+ throw new ArgumentNullException(nameof(name));
+
+ object current = base[name];
+
+ if (current == null)
+ {
+ Put(name, value);
+ }
+ else
+ {
+ IList values = current as IList;
+
+ if (values != null)
+ {
+ values.Add(value);
+ }
+ else
+ {
+ values = new JArray
+ {
+ current,
+ value
+ };
+ Put(name, values);
+ }
+ }
+
+ return this;
+ }
+
+ ///
+ /// Put a key/value pair in the JObject. If the value is null,
+ /// then the key will be removed from the JObject if it is present.
+ ///
+
+ public virtual JObject Put(string name, object value)
+ {
+ if (name == null)
+ throw new ArgumentNullException(nameof(name));
+
+ if (value != null)
+ this[name] = value;
+ else
+ Remove(name);
+
+ return this;
+ }
+
+ public virtual ICollection Names
+ {
+ get
+ {
+ return base.Keys;
+ }
+ }
+
+ ///
+ /// Overridden to return a JSON formatted object as a string.
+ ///
+
+ public override string ToString()
+ {
+ return TextJsonSerializer.SerializeToJayrockCompatibleJson(this);
+ }
+
+
+ }
+}
diff --git a/dotnet/src/dotnetcore/GxClasses/GxClasses.csproj b/dotnet/src/dotnetcore/GxClasses/GxClasses.csproj
index a153ec7c7..b2165e979 100644
--- a/dotnet/src/dotnetcore/GxClasses/GxClasses.csproj
+++ b/dotnet/src/dotnetcore/GxClasses/GxClasses.csproj
@@ -1,13 +1,14 @@
- net6.0
+ net6.0;net8.0
Library
NETCORE;NODATIME
Data Access
GeneXus.Classes.Core
true
618;1607;1698;SYSLIB0021;SYSLIB0027;SYSLIB0028;SYSLIB0023
+ $(TargetsForTfmSpecificContentInPackage);CustomContentTarget
@@ -119,7 +120,6 @@
-
@@ -151,25 +151,31 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
-
-
+
-
+
-
+
@@ -182,11 +188,25 @@
-
-
-
- False
- ..\libs\Jayrock.dll
-
-
+
+
+
+ False
+ ..\libs\net8.0\Jayrock.dll
+
+
+ False
+ ..\libs\Jayrock.dll
+ True
+
+
+
+
+
+ lib/$(TargetFramework)
+ true
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/GxClasses/Helpers/BasicAuthentication.cs b/dotnet/src/dotnetcore/GxClasses/Helpers/BasicAuthentication.cs
index f6d093183..d7cdc1ca2 100644
--- a/dotnet/src/dotnetcore/GxClasses/Helpers/BasicAuthentication.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Helpers/BasicAuthentication.cs
@@ -1,11 +1,11 @@
-using System;
-using System.Collections.Generic;
+using System;
using System.Text;
namespace GxClasses.Helpers
{
public class BasicAuthenticationHeaderValue
{
+ const char UserNamePasswordSeparator= ':';
public BasicAuthenticationHeaderValue(string authenticationHeaderValue)
{
if (!string.IsNullOrWhiteSpace(authenticationHeaderValue))
@@ -19,7 +19,7 @@ public BasicAuthenticationHeaderValue(string authenticationHeaderValue)
}
private readonly string _authenticationHeaderValue;
- private string[] _splitDecodedCredentials;
+ private string _usernamePassword;
public bool IsValidBasicAuthenticationHeaderValue { get; private set; }
public string UserIdentifier { get; private set; }
@@ -32,11 +32,11 @@ private bool TryDecodeHeaderValue()
{
return false;
}
- var encodedCredentials = _authenticationHeaderValue.Substring(headerSchemeLength);
+ string encodedCredentials = _authenticationHeaderValue.Substring(headerSchemeLength);
try
{
- var decodedCredentials = Convert.FromBase64String(encodedCredentials);
- _splitDecodedCredentials = System.Text.Encoding.ASCII.GetString(decodedCredentials).Split(':');
+ byte[] decodedCredentials = Convert.FromBase64String(encodedCredentials);
+ _usernamePassword = Encoding.ASCII.GetString(decodedCredentials);
return true;
}
catch (FormatException)
@@ -47,13 +47,19 @@ private bool TryDecodeHeaderValue()
private void ReadAuthenticationHeaderValue()
{
- IsValidBasicAuthenticationHeaderValue = _splitDecodedCredentials!= null && _splitDecodedCredentials.Length == 2
- && !string.IsNullOrWhiteSpace(_splitDecodedCredentials[0])
- && !string.IsNullOrWhiteSpace(_splitDecodedCredentials[1]);
+ IsValidBasicAuthenticationHeaderValue = !string.IsNullOrEmpty(_usernamePassword) && _usernamePassword.Contains(UserNamePasswordSeparator);
if (IsValidBasicAuthenticationHeaderValue)
{
- UserIdentifier = _splitDecodedCredentials[0];
- UserPassword = _splitDecodedCredentials[1];
+ int separatorIndex = _usernamePassword.IndexOf(UserNamePasswordSeparator);
+ UserIdentifier = _usernamePassword.Substring(0, separatorIndex);
+ if (separatorIndex + 1 < _usernamePassword.Length)
+ {
+ UserPassword = _usernamePassword.Substring(separatorIndex + 1);
+ }
+ else
+ {
+ UserPassword = string.Empty;
+ }
}
}
}
diff --git a/dotnet/src/dotnetcore/GxClasses/Helpers/GXGeographyCore.cs b/dotnet/src/dotnetcore/GxClasses/Helpers/GXGeographyCore.cs
index f4b03d19a..af51f7be6 100644
--- a/dotnet/src/dotnetcore/GxClasses/Helpers/GXGeographyCore.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Helpers/GXGeographyCore.cs
@@ -2,9 +2,13 @@
using System.Collections;
using System.Globalization;
using System.Runtime.Serialization;
+using System.Text.Json.Serialization;
+#if NETCORE
+using GeneXus.Application;
+#else
using Jayrock.Json;
+#endif
using GeographicLib;
-using log4net;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
@@ -202,9 +206,10 @@ internal static object STRingN(object instance, int i)
[KnownType(typeof(System.Double[]))]
[KnownType(typeof(System.Collections.ArrayList))]
[DataContract]
+ [JsonConverter(typeof(CustomGeospatialConverter))]
public class Geospatial : IGeographicNative
{
- static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.Utils.Geospatial));
+ static readonly IGXLogger log = GXLoggerFactory.GetLogger();
internal const string EMPTY_GEOMETRY = "GEOMETRYCOLLECTION EMPTY";
const string EMPTY_GEOGRAPHY = "GEOGRAPHY EMPTY";
@@ -406,7 +411,7 @@ public double Latitude
}
}
- public String JSONPointToWKT(JArray coords)
+ internal String JSONPointToWKT(JArray coords)
{
String[] jbuffer = new String[] { "", "" };
jbuffer[0] = "";
diff --git a/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs b/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs
index 2109ab09c..1c8dea312 100644
--- a/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs
@@ -7,8 +7,14 @@
[assembly: InternalsVisibleTo("AzureFunctionsTest")]
[assembly: InternalsVisibleTo("GXQueue")]
[assembly: InternalsVisibleTo("GXMessageBroker")]
+[assembly: InternalsVisibleTo("GXEventRouter")]
[assembly: InternalsVisibleTo("DotNetCoreUnitTest")]
[assembly: InternalsVisibleTo("DotNetCoreWebUnitTest")]
+[assembly: InternalsVisibleTo("DotNetCoreAttackMitigationTest")]
[assembly: InternalsVisibleTo("GeneXus.Deploy.AzureFunctions.Handlers")]
[assembly: InternalsVisibleTo("AzureFunctionsTest")]
[assembly: InternalsVisibleTo("GXMessageBroker")]
+[assembly: InternalsVisibleTo("GeneXus.SD.Store.StoreManager")]
+[assembly: InternalsVisibleTo("DotNetCoreChunkedTest")]
+[assembly: InternalsVisibleTo("DotNetCoreChunkedTest")]
+[assembly: InternalsVisibleTo("GeneXus.OpenTelemetry.Diagnostics")]
diff --git a/dotnet/src/dotnetcore/GxClasses/Services/LogService/GXLogService.cs b/dotnet/src/dotnetcore/GxClasses/Services/LogService/GXLogService.cs
new file mode 100644
index 000000000..a015eca6d
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxClasses/Services/LogService/GXLogService.cs
@@ -0,0 +1,34 @@
+using System;
+using GeneXus.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace GeneXus.Services.Log
+{
+ public static class GXLogService
+ {
+ private static string AZURE_APPLICATION_INSIGHTS_LOG = "AZUREAPPLICATIONINSIGHTS";
+ const string OTEL_AZUREMONITOR_EXPORTER = "OTEL_AZUREMONITOR_EXPORTER";
+ const string OPENTELEMETRY = "OPENTELEMETRY";
+ internal static string OTEL_LOGS_EXPORTER = "OTEL_LOGS_EXPORTER";
+ const string LOG_OUTPUT = "LOG_OUTPUT";
+
+ public static ILoggerFactory GetLogFactory()
+ {
+ string otelLogEnvVar = Environment.GetEnvironmentVariable(OTEL_LOGS_EXPORTER);
+ if (string.IsNullOrEmpty(otelLogEnvVar) || !otelLogEnvVar.ToLower().Equals("none"))
+ {
+ if (Config.GetValueOf(LOG_OUTPUT, out string logProvider))
+ {
+ if (logProvider == OTEL_AZUREMONITOR_EXPORTER)
+ return OpentelemetryLogProvider.GetAzureMonitorLoggerFactory();
+ else if (logProvider == AZURE_APPLICATION_INSIGHTS_LOG)
+ return OpentelemetryLogProvider.GetAzureAppInsightsLoggerFactory();
+ else
+ if (logProvider == OPENTELEMETRY)
+ return OpentelemetryLogProvider.GetOpentelemetryLoggerFactory();
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/dotnet/src/dotnetcore/GxClasses/Services/LogService/OpenTelemetry/OtelLogProvider.cs b/dotnet/src/dotnetcore/GxClasses/Services/LogService/OpenTelemetry/OtelLogProvider.cs
new file mode 100644
index 000000000..20fef179b
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxClasses/Services/LogService/OpenTelemetry/OtelLogProvider.cs
@@ -0,0 +1,162 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Azure.Monitor.OpenTelemetry.Exporter;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry.Logs;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Exporter;
+
+namespace GeneXus.Services.Log
+{
+ public class OpentelemetryLogProvider : ILoggerFactory
+ {
+ private static string APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING";
+ private const string LOG_LEVEL_ENVVAR = "GX_LOG_LEVEL";
+ public static ILoggerFactory loggerFactory;
+
+ public static ILoggerFactory GetAzureMonitorLoggerFactory()
+ {
+ string appInsightsConnection = Environment.GetEnvironmentVariable(APPLICATIONINSIGHTS_CONNECTION_STRING);
+ try
+ {
+
+ if (appInsightsConnection != null)
+ {
+ LogLevel loglevel = GetLogLevel();
+ loggerFactory = LoggerFactory.Create(builder =>
+ {
+ builder.AddOpenTelemetry(options =>
+ {
+ options.AddAzureMonitorLogExporter(o => o.ConnectionString = appInsightsConnection);
+ if (GenerateOtelLogsToConsole())
+ options.AddConsoleExporter();
+ }).SetMinimumLevel(loglevel);
+ });
+ }
+ else
+ {
+ throw new ArgumentNullException(APPLICATIONINSIGHTS_CONNECTION_STRING, "Opentelemetry Provider is Azure Monitor. Application Insight Log could not be initialized due to missing APPLICATIONINSIGHTS_CONNECTION_STRING environment variable.");
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+
+ return loggerFactory;
+ }
+
+ public static ILoggerFactory GetAzureAppInsightsLoggerFactory()
+ {
+ string appInsightsConnection = Environment.GetEnvironmentVariable(APPLICATIONINSIGHTS_CONNECTION_STRING);
+ try
+ {
+
+ if (appInsightsConnection != null)
+ {
+ LogLevel loglevel = GetLogLevel();
+ loggerFactory = LoggerFactory.Create(builder => builder.AddApplicationInsights(
+
+ configureTelemetryConfiguration: (config) =>
+ config.ConnectionString = appInsightsConnection,
+ configureApplicationInsightsLoggerOptions: (options) => { }
+ ).SetMinimumLevel(loglevel)
+ );
+ }
+ else
+ {
+ throw new ArgumentNullException(APPLICATIONINSIGHTS_CONNECTION_STRING, "LogOutput is Application Insights. Application Insight Log could not be initialized due to missing APPLICATIONINSIGHTS_CONNECTION_STRING environment variable.");
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+
+ return loggerFactory;
+ }
+
+ public static ILoggerFactory GetOpentelemetryLoggerFactory()
+ {
+ LogLevel loglevel = GetLogLevel();
+ loggerFactory = LoggerFactory.Create(builder => builder.AddOpenTelemetry(logging =>
+ {
+ var resourceBuilder = ResourceBuilder.CreateDefault()
+ .AddTelemetrySdk();
+
+ logging.SetResourceBuilder(resourceBuilder)
+ .AddOtlpExporter();
+
+ if (GenerateOtelLogsToConsole())
+ logging.AddConsoleExporter();
+
+ })
+ .SetMinimumLevel(loglevel));
+ return loggerFactory;
+ }
+ private static LogLevel GetLogLevel()
+ {
+ string loglevelvalue = Environment.GetEnvironmentVariable(LOG_LEVEL_ENVVAR);
+ LogLevel loglevel = LogLevel.Information;
+ if (!string.IsNullOrEmpty(loglevelvalue))
+ {
+ if (!Enum.TryParse(loglevelvalue, out loglevel))
+ {
+ CustomLogLevel customLogLevel = CustomLogLevel.info;
+ if (Enum.TryParse(loglevelvalue, out customLogLevel))
+ {
+ loglevel = toLogLevel(customLogLevel);
+ }
+ else
+ loglevel = LogLevel.Information;
+ }
+ }
+ return loglevel;
+ }
+
+ private static bool GenerateOtelLogsToConsole()
+ {
+ string otelLogsEnvVar = Environment.GetEnvironmentVariable(GXLogService.OTEL_LOGS_EXPORTER);
+ if (string.IsNullOrEmpty(otelLogsEnvVar)) { return false; }
+ return otelLogsEnvVar.ToLower().Contains("console") || otelLogsEnvVar.ToLower().Contains("logging");
+ }
+
+ public void AddProvider(ILoggerProvider provider)
+ {
+ loggerFactory.AddProvider(provider);
+ }
+ public void Dispose()
+ {
+ loggerFactory.Dispose();
+ }
+ public ILogger CreateLogger(string name)
+ {
+ return loggerFactory.CreateLogger(name);
+ }
+ private enum CustomLogLevel
+ {
+ none,
+ all,
+ debug,
+ info,
+ warn,
+ error,
+ fatal
+ }
+ private static LogLevel toLogLevel(CustomLogLevel customLogLevel)
+ {
+ switch (customLogLevel)
+ {
+ case CustomLogLevel.none: return LogLevel.None;
+ case CustomLogLevel.all: return LogLevel.Trace;
+ case CustomLogLevel.debug: return LogLevel.Debug;
+ case CustomLogLevel.info: return LogLevel.Information;
+ case CustomLogLevel.warn: return LogLevel.Warning;
+ case CustomLogLevel.error: return LogLevel.Error;
+ case CustomLogLevel.fatal: return LogLevel.Critical;
+ default: return LogLevel.Information;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/GxClasses/Services/OpenTelemetry/OpenTelemetryService.cs b/dotnet/src/dotnetcore/GxClasses/Services/OpenTelemetry/OpenTelemetryService.cs
index 125f05ff5..3dfdf2b00 100644
--- a/dotnet/src/dotnetcore/GxClasses/Services/OpenTelemetry/OpenTelemetryService.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Services/OpenTelemetry/OpenTelemetryService.cs
@@ -1,6 +1,6 @@
using System;
+using System.Text.RegularExpressions;
using GxClasses.Helpers;
-using log4net;
namespace GeneXus.Services.OpenTelemetry
{
@@ -11,10 +11,56 @@ public interface IOpenTelemetryProvider
public static class OpenTelemetryService
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(OpenTelemetryService));
- private static string OPENTELEMETRY_SERVICE = "Observability";
- public static string GX_ACTIVITY_SOURCE_NAME = "GeneXus.Tracing";
-
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger(typeof(OpenTelemetryService).FullName);
+
+ const string OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES";
+ const string OTEL_SERVICE_NAME = "OTEL_SERVICE_NAME";
+ const string OTEL_SERVICE_VERSION = "OTEL_SERVICE_VERSION";
+ const string OPENTELEMETRY_SERVICE = "Observability";
+
+ public static string GX_ACTIVITY_SOURCE_NAME= GetServiceNameValue(OTEL_RESOURCE_ATTRIBUTES);
+ public static string GX_ACTIVITY_SOURCE_VERSION= GetServiceVersionValue(OTEL_RESOURCE_ATTRIBUTES);
+
+ private static string GetServiceNameValue(string input)
+ {
+ string otelServiceNameEnvVar = Environment.GetEnvironmentVariable(OTEL_SERVICE_NAME);
+ if (!string.IsNullOrEmpty(otelServiceNameEnvVar))
+ return otelServiceNameEnvVar;
+
+ string pattern = @"(?:\b\w+\b=\w+)(?:,(?:\b\w+\b=\w+))*";
+ MatchCollection matches = Regex.Matches(input, pattern);
+
+ foreach (Match match in matches)
+ {
+ string[] keyValue = match.Value.Split('=');
+
+ if (keyValue[0] == "service.name")
+ {
+ return keyValue[1];
+ }
+ }
+ return "GeneXus.Tracing";
+ }
+ private static string GetServiceVersionValue(string input)
+ {
+ string otelServiceNameEnvVar = Environment.GetEnvironmentVariable(OTEL_SERVICE_VERSION);
+ if (!string.IsNullOrEmpty(otelServiceNameEnvVar))
+ return otelServiceNameEnvVar;
+
+ string pattern = @"(?:\b\w+\b=\w+)(?:,(?:\b\w+\b=\w+))*";
+ MatchCollection matches = Regex.Matches(input, pattern);
+
+ foreach (Match match in matches)
+ {
+ string[] keyValue = match.Value.Split('=');
+
+ if (keyValue[0] == "service.version")
+ {
+ return keyValue[1];
+ }
+ }
+ return string.Empty;
+ }
private static IOpenTelemetryProvider GetOpenTelemetryProvider()
{
IOpenTelemetryProvider otelProvider = null;
@@ -34,7 +80,7 @@ private static IOpenTelemetryProvider GetOpenTelemetryProvider()
}
catch (Exception e)
{
- GXLogging.Error(log, "Couldn´t create OpenTelemetry provider.", e.Message, e);
+ GXLogging.Error(log, "Couldn't create OpenTelemetry provider.", e.Message, e);
throw e;
}
}
@@ -49,7 +95,7 @@ internal static void Setup(Microsoft.Extensions.DependencyInjection.IServiceColl
bool started = provider.InstrumentAspNetCoreApplication(services);
if (started)
{
- log.Info("OpenTelemetry instrumentation started");
+ GXLogging.Info(log, "OpenTelemetry instrumentation started");
}
}
}
diff --git a/dotnet/src/dotnetcore/GxClasses/Services/ServiceSettings.cs b/dotnet/src/dotnetcore/GxClasses/Services/ServiceSettings.cs
index 2249548f0..a9ab19878 100644
--- a/dotnet/src/dotnetcore/GxClasses/Services/ServiceSettings.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Services/ServiceSettings.cs
@@ -1,12 +1,11 @@
using System;
using GeneXus.Encryption;
-using log4net;
namespace GeneXus.Services.Common
{
public class ServiceSettingsReader
{
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(ServiceSettingsReader));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
internal GXService service;
public string serviceNameResolver { get; }
@@ -25,7 +24,7 @@ public string GetEncryptedPropertyValue(string propertyName)
if (value == null)
{
String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
- logger.Fatal(errorMessage);
+ GXLogging.Critical(logger, errorMessage);
throw new Exception(errorMessage);
}
return value;
@@ -45,7 +44,7 @@ public string GetEncryptedPropertyValue(string propertyName, string defaultValue
}
catch (Exception)
{
- logger.Warn($"Could not decrypt property name: {ResolvePropertyName(propertyName)}");
+ GXLogging.Warn(logger, $"Could not decrypt property name: {ResolvePropertyName(propertyName)}");
}
}
return value;
@@ -57,7 +56,7 @@ public string GetPropertyValue(string propertyName)
if (value == null)
{
String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
- logger.Fatal(errorMessage);
+ GXLogging.Critical(logger, errorMessage);
throw new Exception(errorMessage);
}
return value;
diff --git a/dotnet/src/dotnetcore/GxClasses/Services/Session/GXSessionFactory.cs b/dotnet/src/dotnetcore/GxClasses/Services/Session/GXSessionFactory.cs
index 51e578ce0..79a8b5827 100644
--- a/dotnet/src/dotnetcore/GxClasses/Services/Session/GXSessionFactory.cs
+++ b/dotnet/src/dotnetcore/GxClasses/Services/Session/GXSessionFactory.cs
@@ -5,13 +5,13 @@
using GeneXus.Data.ADO;
using GeneXus.Encryption;
using GxClasses.Helpers;
-using log4net;
namespace GeneXus.Services
{
public class GXSessionServiceFactory
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GXSessionServiceFactory));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
+
static string REDIS = "REDIS";
static string DATABASE = "DATABASE";
public static ISessionService GetProvider()
@@ -58,7 +58,7 @@ public static ISessionService GetProvider()
}
public class GxRedisSession : ISessionService
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GxRedisSession));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
internal static string SESSION_ADDRESS = "SESSION_PROVIDER_ADDRESS";
internal static string SESSION_INSTANCE = "SESSION_PROVIDER_INSTANCE_NAME";
internal static string SESSION_PASSWORD = "SESSION_PROVIDER_PASSWORD";
@@ -108,7 +108,7 @@ public GxRedisSession(string host, string password, string instanceName, int ses
}
public class GxDatabaseSession : ISessionService
{
- private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GxDatabaseSession));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
internal static string SESSION_ADDRESS = "SESSION_PROVIDER_ADDRESS";
internal static string SESSION_PASSWORD = "SESSION_PROVIDER_PASSWORD";
internal static string SESSION_SCHEMA = "SESSION_PROVIDER_SCHEMA";
diff --git a/dotnet/src/dotnetcore/GxDataInitialization/GXDataInitialization.csproj b/dotnet/src/dotnetcore/GxDataInitialization/GXDataInitialization.csproj
index 7c41acaec..31547472d 100644
--- a/dotnet/src/dotnetcore/GxDataInitialization/GXDataInitialization.csproj
+++ b/dotnet/src/dotnetcore/GxDataInitialization/GXDataInitialization.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
Exe
DataInitialization
GeneXus.DataInitialization.Core
@@ -12,6 +12,10 @@
+
+
+
+
@@ -19,11 +23,11 @@
- contentFiles/any/any
+ contentFiles/any/$(TargetFramework)
true
- contentFiles/any/any
+ contentFiles/any/$(TargetFramework)
true
diff --git a/dotnet/src/dotnetcore/GxExcel/GxExcel.csproj b/dotnet/src/dotnetcore/GxExcel/GxExcel.csproj
index 15df73743..916d3c26d 100644
--- a/dotnet/src/dotnetcore/GxExcel/GxExcel.csproj
+++ b/dotnet/src/dotnetcore/GxExcel/GxExcel.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
NETCORE
GxExcelI
EPPlus Lite
@@ -16,9 +16,9 @@
+
-
-
+
diff --git a/dotnet/src/dotnetcore/GxMail/GxMail.csproj b/dotnet/src/dotnetcore/GxMail/GxMail.csproj
index 0b7d837ce..f8899a0f6 100644
--- a/dotnet/src/dotnetcore/GxMail/GxMail.csproj
+++ b/dotnet/src/dotnetcore/GxMail/GxMail.csproj
@@ -1,7 +1,7 @@
- net6.0
- 1701;1702;NU1701
+ net6.0;net8.0
+ 1701;1702;NU1701;CS0618
NETCORE
SMTP Exchange POP3
GeneXus.Mail.Core
@@ -66,11 +66,11 @@
-
+
-
+
diff --git a/dotnet/src/dotnetcore/GxMaps/GxMaps.csproj b/dotnet/src/dotnetcore/GxMaps/GxMaps.csproj
index 128f906e0..dc95fa2c3 100644
--- a/dotnet/src/dotnetcore/GxMaps/GxMaps.csproj
+++ b/dotnet/src/dotnetcore/GxMaps/GxMaps.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
1701;1702;NU1701
NETCORE
Maps
@@ -13,10 +13,9 @@
-
- False
- ..\libs\Jayrock.dll
-
+
+
+
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/GxNetCoreStartup/CsrfHelper.cs b/dotnet/src/dotnetcore/GxNetCoreStartup/CsrfHelper.cs
new file mode 100644
index 000000000..2020e7371
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxNetCoreStartup/CsrfHelper.cs
@@ -0,0 +1,69 @@
+
+
+using System;
+using System.Threading.Tasks;
+using GeneXus.Configuration;
+using GeneXus.Http;
+using Microsoft.AspNetCore.Antiforgery;
+using Microsoft.AspNetCore.Http;
+namespace GeneXus.Application
+{
+ public class ValidateAntiForgeryTokenMiddleware
+ {
+ static readonly IGXLogger log = GXLoggerFactory.GetLogger();
+ private readonly RequestDelegate _next;
+ private readonly IAntiforgery _antiforgery;
+ private string _restBasePath;
+ private string _basePath;
+
+ public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery, string basePath)
+ {
+ _next = next;
+ _antiforgery = antiforgery;
+ _restBasePath = $"{basePath}{Startup.REST_BASE_URL}";
+ _basePath = $"/{basePath}";
+ }
+
+ public async Task Invoke(HttpContext context)
+ {
+ if (context.Request.Path.HasValue && context.Request.Path.Value.StartsWith(_basePath))
+ {
+ if (HttpMethods.IsPost(context.Request.Method) ||
+ HttpMethods.IsDelete(context.Request.Method) ||
+ HttpMethods.IsPut(context.Request.Method))
+ {
+ string cookieToken = context.Request.Cookies[HttpHeader.X_CSRF_TOKEN_COOKIE];
+ string headerToken = context.Request.Headers[HttpHeader.X_CSRF_TOKEN_HEADER];
+ GXLogging.Debug(log, $"Antiforgery validation, cookieToken:{cookieToken}, headerToken:{headerToken}");
+
+ await _antiforgery.ValidateRequestAsync(context);
+ GXLogging.Debug(log, $"Antiforgery validation OK");
+ }
+ else if (HttpMethods.IsGet(context.Request.Method))
+ {
+ SetAntiForgeryTokens(_antiforgery, context);
+ }
+ }
+ if (!IsVerificationTokenServiceRequest(context))
+ await _next(context);
+ }
+ private bool IsVerificationTokenServiceRequest(HttpContext context)
+ {
+ return context.Request.Path.Value.EndsWith(_restBasePath);
+ }
+ internal static void SetAntiForgeryTokens(IAntiforgery _antiforgery, HttpContext context)
+ {
+ AntiforgeryTokenSet tokenSet = _antiforgery.GetAndStoreTokens(context);
+ string sameSite;
+ CookieOptions cookieOptions = new CookieOptions { HttpOnly = false, Secure = GxContext.GetHttpSecure(context) == 1 };
+ SameSiteMode sameSiteMode = SameSiteMode.Unspecified;
+ if (Config.GetValueOf("SAMESITE_COOKIE", out sameSite) && Enum.TryParse(sameSite, out sameSiteMode))
+ {
+ cookieOptions.SameSite = sameSiteMode;
+ }
+ context.Response.Cookies.Append(HttpHeader.X_CSRF_TOKEN_COOKIE, tokenSet.RequestToken, cookieOptions);
+ GXLogging.Debug(log, $"Setting cookie ", HttpHeader.X_CSRF_TOKEN_COOKIE, "=", tokenSet.RequestToken, " samesite:" + sameSiteMode);
+ }
+
+ }
+}
diff --git a/dotnet/src/dotnetcore/GxNetCoreStartup/GxNetCoreStartup.csproj b/dotnet/src/dotnetcore/GxNetCoreStartup/GxNetCoreStartup.csproj
index 2118c21f1..522adb9f8 100644
--- a/dotnet/src/dotnetcore/GxNetCoreStartup/GxNetCoreStartup.csproj
+++ b/dotnet/src/dotnetcore/GxNetCoreStartup/GxNetCoreStartup.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
GxNetCoreStartup
GeneXus.NetCoreStartup
true
@@ -10,33 +10,38 @@
-
-
-
+
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
- False
- ..\libs\Jayrock.dll
-
-
- contentFiles/any/any
+ contentFiles/any/$(TargetFramework)
true
- contentFiles/any/any
+ contentFiles/any/$(TargetFramework)
true
diff --git a/dotnet/src/dotnetcore/GxNetCoreStartup/Properties/AssemblyInfo.cs b/dotnet/src/dotnetcore/GxNetCoreStartup/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..e3c540157
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxNetCoreStartup/Properties/AssemblyInfo.cs
@@ -0,0 +1,7 @@
+using System.Runtime.CompilerServices;
+
+
+[assembly: InternalsVisibleTo("DotNetCoreOpenTelemetryTest")]
+[assembly: InternalsVisibleTo("DotNetCoreWebUnitTest")]
+
+
diff --git a/dotnet/src/dotnetcore/GxNetCoreStartup/Startup.cs b/dotnet/src/dotnetcore/GxNetCoreStartup/Startup.cs
index a5d8ceed3..b90fd4050 100644
--- a/dotnet/src/dotnetcore/GxNetCoreStartup/Startup.cs
+++ b/dotnet/src/dotnetcore/GxNetCoreStartup/Startup.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Net;
+using System.Reflection;
using System.Threading.Tasks;
using GeneXus.Configuration;
using GeneXus.Http;
@@ -10,14 +11,15 @@
using GeneXus.Services.OpenTelemetry;
using GeneXus.Utils;
using GxClasses.Web.Middleware;
-using log4net;
using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.AspNetCore.Routing;
@@ -29,13 +31,13 @@
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
-
namespace GeneXus.Application
{
public class Program
{
const string DEFAULT_PORT = "80";
static string DEFAULT_SCHEMA = Uri.UriSchemeHttp;
+
public static void Main(string[] args)
{
try
@@ -74,10 +76,9 @@ public static void Main(string[] args)
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
- .ConfigureLogging(logging => logging.AddConsole())
- .UseStartup()
- .UseContentRoot(Startup.LocalPath)
- .Build();
+ .UseStartup()
+ .UseContentRoot(Startup.LocalPath)
+ .Build();
public static IWebHost BuildWebHostPort(string[] args, string port)
{
@@ -86,12 +87,13 @@ public static IWebHost BuildWebHostPort(string[] args, string port)
static IWebHost BuildWebHostPort(string[] args, string port, string schema)
{
return WebHost.CreateDefaultBuilder(args)
- .ConfigureLogging(logging => logging.AddConsole())
.UseUrls($"{schema}://*:{port}")
.UseStartup()
+ .UseWebRoot(Startup.LocalPath)
.UseContentRoot(Startup.LocalPath)
.Build();
}
+
private static void LocatePhysicalLocalPath()
{
string startup = FileUtil.GetStartupDirectory();
@@ -99,11 +101,14 @@ private static void LocatePhysicalLocalPath()
if (startup == Startup.LocalPath && !File.Exists(Path.Combine(startup, Startup.APP_SETTINGS)) && File.Exists(Path.Combine(startupParent, Startup.APP_SETTINGS)))
Startup.LocalPath = startupParent;
}
-
}
public static class GXHandlerExtensions
{
+ public static IApplicationBuilder UseAntiforgeryTokens(this IApplicationBuilder app, string basePath)
+ {
+ return app.UseMiddleware(basePath);
+ }
public static IApplicationBuilder UseGXHandlerFactory(this IApplicationBuilder builder, string basePath)
{
return builder.UseMiddleware(basePath);
@@ -117,9 +122,10 @@ public static IApplicationBuilder MapWebSocketManager(this IApplicationBuilder a
}
public class Startup
- {
+ {
+ static IGXLogger log;
+ internal static string APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING";
- static readonly ILog log = log4net.LogManager.GetLogger(typeof(Startup));
const long DEFAULT_MAX_FILE_UPLOAD_SIZE_BYTES = 528000000;
public static string VirtualPath = string.Empty;
public static string LocalPath = Directory.GetCurrentDirectory();
@@ -129,7 +135,7 @@ public class Startup
const string RESOURCES_FOLDER = "Resources";
const string TRACE_FOLDER = "logs";
const string TRACE_PATTERN = "trace.axd";
- const string REST_BASE_URL = "rest/";
+ internal const string REST_BASE_URL = "rest/";
const string DATA_PROTECTION_KEYS = "DataProtection-Keys";
const string REWRITE_FILE = "rewrite.config";
const string SWAGGER_DEFAULT_YAML = "default.yaml";
@@ -138,35 +144,59 @@ public class Startup
const string CORS_POLICY_NAME = "AllowSpecificOriginsPolicy";
const string CORS_ANY_ORIGIN = "*";
const double CORS_MAX_AGE_SECONDS = 86400;
+ internal const string GX_CONTROLLERS = "gxcontrollers";
public List servicesBase = new List();
private GXRouting gxRouting;
-
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
Config.ConfigRoot = configuration;
+ GxContext.IsHttpContext = true;
+ Config.LoadConfiguration();
GXRouting.ContentRootPath = env.ContentRootPath;
GXRouting.UrlTemplateControllerWithParms = "controllerWithParms";
- GxContext.IsHttpContext = true;
gxRouting = new GXRouting(REST_BASE_URL);
+ log = GXLoggerFactory.GetLogger();
}
public void ConfigureServices(IServiceCollection services)
{
OpenTelemetryService.Setup(services);
- services.AddMvc(option => option.EnableEndpointRouting = false);
+ services.AddControllers();
+ string controllers = Path.Combine(Startup.LocalPath, "bin", GX_CONTROLLERS);
+ IMvcBuilder mvcBuilder = services.AddMvc(option => option.EnableEndpointRouting = false);
+ try
+ {
+ if (Directory.Exists(controllers))
+ {
+ foreach (string controller in Directory.GetFiles(controllers))
+ {
+ Console.WriteLine($"Loading controller {controller}");
+ mvcBuilder.AddApplicationPart(Assembly.LoadFrom(controller)).AddControllersAsServices();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine("Error loading gxcontrollers " + ex.Message);
+ }
services.Configure(options =>
{
options.AllowSynchronousIO = true;
options.Limits.MaxRequestBodySize = null;
+ if (Config.GetValueOrEnvironmentVarOf("MinRequestBodyDataRate", out string MinRequestBodyDataRateStr) && double.TryParse(MinRequestBodyDataRateStr, out double MinRequestBodyDataRate))
+ {
+ GXLogging.Info(log, $"MinRequestBodyDataRate:{MinRequestBodyDataRate}");
+ options.Limits.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: MinRequestBodyDataRate, gracePeriod: TimeSpan.FromSeconds(10));
+ }
});
services.Configure(options =>
{
options.AllowSynchronousIO = true;
});
services.AddDistributedMemoryCache();
-
+ services.AddLogging(builder => builder.AddConsole());
services.Configure(options =>
{
if (Config.GetValueOf("MaxFileUploadSize", out string MaxFileUploadSizeStr) && long.TryParse(MaxFileUploadSizeStr, out long MaxFileUploadSize))
@@ -191,6 +221,12 @@ public void ConfigureServices(IServiceCollection services)
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.IsEssential = true;
+ string sessionCookieName = GxWebSession.GetSessionCookieName(VirtualPath);
+ if (!string.IsNullOrEmpty(sessionCookieName))
+ {
+ options.Cookie.Name=sessionCookieName;
+ GxWebSession.SessionCookieName = sessionCookieName;
+ }
string sameSite;
SameSiteMode sameSiteMode = SameSiteMode.Unspecified;
if (Config.GetValueOf("SAMESITE_COOKIE", out sameSite) && Enum.TryParse(sameSite, out sameSiteMode))
@@ -199,7 +235,14 @@ public void ConfigureServices(IServiceCollection services)
}
});
-
+ if (RestAPIHelpers.ValidateCsrfToken())
+ {
+ services.AddAntiforgery(options =>
+ {
+ options.HeaderName = HttpHeader.X_CSRF_TOKEN_HEADER;
+ options.SuppressXFrameOptionsHeader = true;
+ });
+ }
services.AddDirectoryBrowser();
if (GXUtil.CompressResponse())
{
@@ -224,7 +267,6 @@ public void ConfigureServices(IServiceCollection services)
});
}
DefineCorsPolicy(services);
- services.AddMvc();
}
private void DefineCorsPolicy(IServiceCollection services)
@@ -285,7 +327,8 @@ private void ConfigureSessionService(IServiceCollection services, ISessionServic
public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env, ILoggerFactory loggerFactory)
{
string baseVirtualPath = string.IsNullOrEmpty(VirtualPath) ? VirtualPath : $"/{VirtualPath}";
- LogConfiguration.SetupLog4Net();
+ LogConfiguration.SetupLog4Net();
+
var provider = new FileExtensionContentTypeProvider();
//mappings
provider.Mappings[".json"] = "application/json";
@@ -304,10 +347,12 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
provider.Mappings[".usdz"] = "model/vnd.pixar.usd";
provider.Mappings[".sfb"] = "model/sfb";
provider.Mappings[".gltf"] = "model/gltf+json";
+ provider.Mappings[".ini"] = "text/plain";
if (GXUtil.CompressResponse())
{
app.UseResponseCompression();
}
+ app.UseRouting();
app.UseCookiePolicy();
app.UseSession();
app.UseStaticFiles();
@@ -330,6 +375,10 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
app.UseHttpsRedirection();
app.UseHsts();
}
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
if (log.IsDebugEnabled)
{
try
@@ -357,14 +406,22 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
if (File.Exists(rewriteFile))
AddRewrite(app, rewriteFile, baseVirtualPath);
+ string tempMediaDir = string.Empty;
+ if (Config.GetValueOf("TMPMEDIA_DIR", out string mediaPath) && !PathUtil.IsAbsoluteUrlOrAnyScheme(mediaPath))
+ {
+ tempMediaDir = mediaPath;
+ }
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(LocalPath),
RequestPath = new PathString($"{baseVirtualPath}"),
OnPrepareResponse = s =>
{
- var path = s.Context.Request.Path;
- if (path.HasValue && path.Value.IndexOf($"/{APP_SETTINGS}", StringComparison.OrdinalIgnoreCase)>=0)
+ PathString path = s.Context.Request.Path;
+ bool appSettingsPath = path.HasValue && path.Value.IndexOf($"/{APP_SETTINGS}", StringComparison.OrdinalIgnoreCase) >= 0;
+ bool tempMediaPath = path.StartsWithSegments($"{baseVirtualPath}/{tempMediaDir}", StringComparison.OrdinalIgnoreCase);
+ bool privatePath = path.StartsWithSegments($"{baseVirtualPath}/{GXRouting.PRIVATE_DIR}", StringComparison.OrdinalIgnoreCase);
+ if (appSettingsPath || tempMediaPath || privatePath)
{
s.Context.Response.StatusCode = 401;
s.Context.Response.Body = Stream.Null;
@@ -386,6 +443,12 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
string restBasePath = string.IsNullOrEmpty(VirtualPath) ? REST_BASE_URL : $"{VirtualPath}/{REST_BASE_URL}";
string apiBasePath = string.IsNullOrEmpty(VirtualPath) ? string.Empty : $"{VirtualPath}/";
+ IAntiforgery antiforgery = null;
+ if (RestAPIHelpers.ValidateCsrfToken())
+ {
+ antiforgery = app.ApplicationServices.GetRequiredService();
+ app.UseAntiforgeryTokens(apiBasePath);
+ }
app.UseMvc(routes =>
{
foreach (string serviceBasePath in servicesBase)
@@ -400,10 +463,10 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
routes.MapRoute($"{restBasePath}{{*{UrlTemplateControllerWithParms}}}", new RequestDelegate(gxRouting.ProcessRestRequest));
routes.MapRoute("Default", VirtualPath, new { controller = "Home", action = "Index" });
});
-
+
app.UseWebSockets();
string basePath = string.IsNullOrEmpty(VirtualPath) ? string.Empty : $"/{VirtualPath}";
- Config.ScriptPath = basePath;
+ Config.ScriptPath = string.IsNullOrEmpty(basePath) ? "/" : basePath;
app.MapWebSocketManager(basePath);
app.MapWhen(
@@ -474,9 +537,10 @@ bool IsAspx(HttpContext context, string basePath)
}
public class CustomExceptionHandlerMiddleware
{
- static readonly ILog log = log4net.LogManager.GetLogger(typeof(CustomExceptionHandlerMiddleware));
+ static readonly IGXLogger log = GXLoggerFactory.GetLogger();
public async Task Invoke(HttpContext httpContext)
{
+ string httpReasonPhrase=string.Empty;
Exception ex = httpContext.Features.Get()?.Error;
HttpStatusCode httpStatusCode = (HttpStatusCode)httpContext.Response.StatusCode;
if (ex!=null)
@@ -485,6 +549,12 @@ public async Task Invoke(HttpContext httpContext)
{
httpStatusCode = HttpStatusCode.NotFound;
}
+ else if (ex is AntiforgeryValidationException)
+ {
+ httpStatusCode = HttpStatusCode.BadRequest;
+ httpReasonPhrase = HttpHelper.InvalidCSRFToken;
+ GXLogging.Error(log, $"Validation of antiforgery failed", ex);
+ }
else
{
httpStatusCode = HttpStatusCode.InternalServerError;
@@ -495,13 +565,19 @@ public async Task Invoke(HttpContext httpContext)
{
string redirectPage = Config.MapCustomError(httpStatusCode.ToString(HttpHelper.INT_FORMAT));
if (!string.IsNullOrEmpty(redirectPage))
-{
+ {
httpContext.Response.Redirect($"{httpContext.Request.GetApplicationPath()}/{redirectPage}");
}
else
{
httpContext.Response.StatusCode = (int)httpStatusCode;
}
+ if (!string.IsNullOrEmpty(httpReasonPhrase))
+ {
+ IHttpResponseFeature responseReason = httpContext.Response.HttpContext.Features.Get();
+ if (responseReason!=null)
+ responseReason.ReasonPhrase = httpReasonPhrase;
+ }
}
await Task.CompletedTask;
}
diff --git a/dotnet/src/dotnetcore/GxOffice/GxOffice.csproj b/dotnet/src/dotnetcore/GxOffice/GxOffice.csproj
index 4a31a7b68..094c0b13e 100644
--- a/dotnet/src/dotnetcore/GxOffice/GxOffice.csproj
+++ b/dotnet/src/dotnetcore/GxOffice/GxOffice.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
NETCORE
Genexus.Office
GxOffice
@@ -35,8 +35,8 @@
-
+
diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/GlobalSuppressions.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/GlobalSuppressions.cs
index 37a5076e3..74e1befce 100644
--- a/dotnet/src/dotnetcore/GxPdfReportsCS/GlobalSuppressions.cs
+++ b/dotnet/src/dotnetcore/GxPdfReportsCS/GlobalSuppressions.cs
@@ -16,3 +16,5 @@
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "", Scope = "member", Target = "~M:com.genexus.reports.NativeSharpFunctionsMS.getRegistrySubValues(System.String,System.String)~System.Collections.ArrayList")]
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "", Scope = "member", Target = "~M:com.genexus.reports.NativeSharpFunctionsMS.ReadRegKey(System.String)~System.String")]
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "", Scope = "member", Target = "~M:com.genexus.reports.MSPDFFontDescriptor.getTrueTypeFontLocation(System.String)~System.String")]
+[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "", Scope = "member", Target = "~M:com.genexus.reports.PDFReportBase.getAcrobatLocation~System.String")]
+[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "", Scope = "member", Target = "~M:com.genexus.reports.PDFReportBase.loadSubstituteTable")]
diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/GxPdfReportsCS.csproj b/dotnet/src/dotnetcore/GxPdfReportsCS/GxPdfReportsCS.csproj
index 6f996b82c..95fa355b4 100644
--- a/dotnet/src/dotnetcore/GxPdfReportsCS/GxPdfReportsCS.csproj
+++ b/dotnet/src/dotnetcore/GxPdfReportsCS/GxPdfReportsCS.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
1701;1702;NU1701
NETCORE
Itext PDF Report
@@ -9,12 +9,23 @@
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs
new file mode 100644
index 000000000..c927b8281
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportItext8.cs
@@ -0,0 +1,1330 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using GeneXus;
+using iText.Barcodes;
+using iText.Html2pdf;
+using iText.Html2pdf.Resolver.Font;
+using iText.IO.Font;
+using iText.IO.Font.Otf;
+using iText.IO.Image;
+using iText.Kernel.Colors;
+using iText.Kernel.Exceptions;
+using iText.Kernel.Font;
+using iText.Kernel.Geom;
+using iText.Kernel.Pdf;
+using iText.Kernel.Pdf.Action;
+using iText.Kernel.Pdf.Canvas;
+using iText.Layout;
+using iText.Layout.Borders;
+using iText.Layout.Element;
+using iText.Layout.Font;
+using iText.Layout.Layout;
+using iText.Layout.Properties;
+using iText.Layout.Splitting;
+using Path = System.IO.Path;
+
+namespace GeneXus.Printer
+{
+ public class GxReportBuilderPdf8 : GxReportBuilderPdf
+ {
+ static IGXLogger log = GXLoggerFactory.GetLogger();
+ public GxReportBuilderPdf8() { }
+ public GxReportBuilderPdf8(string appPath, Stream outputStream)
+ {
+ _appPath = appPath;
+ _pdfReport = new com.genexus.reports.PDFReportItext8(appPath);
+ if (outputStream != null)
+ {
+ _pdfReport.setOutputStream(outputStream);
+ GXLogging.Debug(log, "GxReportBuilderPdf outputStream: binaryWriter");
+ }
+ }
+ }
+
+}
+namespace com.genexus.reports
+{
+
+ public class PDFReportItext8 : PDFReportBase
+ {
+ static IGXLogger log = GXLoggerFactory.GetLogger();
+
+ //const int ASCENT_NORMALIZED_UNITS = 1000;
+
+ private PageSize pageSize;
+ private PdfFont baseFont;
+ private Style fontStyle;
+ //Color for, BaseColor for => Itext5
+ private Color backColor, foreColor, templateColorFill;
+ private Document document;
+ PdfDocument pdfDocument;
+ private PdfPage pdfPage;
+ private PdfWriter writer;
+ private Rectangle templateRectangle;
+ private float templatex, templatey;
+ private PdfFont templateFont;
+ private PdfFont defaultFont;
+ internal Dictionary documentImages;
+ Barcode128 barcode;
+ private Boolean fontBold;
+ private Boolean fontItalic;
+
+ public PDFReportItext8(String appPath) : base(appPath)
+ {
+ documentImages = new Dictionary();
+ }
+
+ protected override void init(ref int gxYPage, ref int gxXPage, int pageWidth, int pageLength)
+ {
+ this.pageSize = ComputePageSize(leftMargin, topMargin, pageWidth, pageLength, props.getBooleanGeneralProperty(Const.MARGINS_INSIDE_BORDER, Const.DEFAULT_MARGINS_INSIDE_BORDER));
+ gxXPage = (int)this.pageSize.GetRight();
+ if (props.getBooleanGeneralProperty(Const.FIX_SAC24437, true))
+ gxYPage = (int)(pageLength / GX_PAGE_SCALE_Y);
+ else
+ gxYPage = (int)(pageLength / GX_PAGE_SCALE_Y_OLD);
+
+ writer = new PdfWriter(outputStream);
+ writer.SetCompressionLevel(CompressionConstants.BEST_COMPRESSION);
+ try
+ {
+ string level = props.getGeneralProperty(Const.COMPLIANCE_LEVEL);
+ if (Enum.TryParse(level, true, out complianceLevel))
+ {
+ //if (SetComplainceLevel(complianceLevel))
+ //writer.SetTagged();
+ }
+ pdfDocument = new PdfDocument(writer);
+ pdfDocument.SetDefaultPageSize(this.pageSize);
+ document = new Document(pdfDocument);
+ document.SetFontProvider(new DefaultFontProvider(false, false, false));
+ }
+ catch (PdfException de)
+ {
+ GXLogging.Debug(log, "GxDrawRect error", de);
+ }
+ }
+
+ internal override bool SetComplainceLevel(PdfConformanceLevel level)
+ {
+ /*switch (level)
+ {
+ case PdfConformanceLevel.Pdf_A1A:
+ writer.PDFXConformance = PdfWriter.PDFA1A;
+ return true;
+ case PdfConformanceLevel.Pdf_A1B:
+ writer.PDFXConformance = PdfWriter.PDFA1B;
+ return true;
+ default:
+ return false;
+ }*/
+ return false;
+ }
+
+ /**
+ * @param hideCorners indicates whether corner triangles should be hidden when the side that joins them is hidden.
+ */
+
+ private void drawRectangle(PdfCanvas cb, float x, float y, float w, float h, int styleTop, int styleBottom, int styleRight, int styleLeft,
+ float radioTL, float radioTR, float radioBL, float radioBR, float penAux, bool hideCorners)
+ {
+
+ float[] dashPatternTop = getDashedPattern(styleTop);
+ float[] dashPatternBottom = getDashedPattern(styleBottom);
+ float[] dashPatternLeft = getDashedPattern(styleLeft);
+ float[] dashPatternRight = getDashedPattern(styleRight);
+
+ //-------------------bottom line---------------------
+ if (styleBottom != STYLE_NONE_CONST)
+ {
+ cb.SetLineDash(dashPatternBottom, 0);
+ }
+
+ float b = 0.4477f;
+ if (radioBL > 0)
+ {
+ cb.MoveTo(x + radioBL, y);
+ }
+ else
+ {
+ if (hideCorners && styleLeft == STYLE_NONE_CONST && radioBL == 0)
+ {
+ cb.MoveTo(x + penAux, y);
+ }
+ else
+ {
+ cb.MoveTo(x, y);
+ }
+ }
+
+ //-------------------bottom right corner---------------------
+
+ if (styleBottom != STYLE_NONE_CONST)
+ {
+ if (hideCorners && styleRight == STYLE_NONE_CONST && radioBR == 0)
+ {
+ cb.LineTo(x + w - penAux, y);
+ }
+ else
+ {
+ cb.LineTo(x + w - radioBR, y);
+ }
+ if (radioBR > 0 && styleRight != STYLE_NONE_CONST)
+ {
+ cb.CurveTo(x + w - radioBR * b, y, x + w, y + radioBR * b, x + w, y + radioBR);
+ }
+ }
+
+ //-------------------right line---------------------
+
+ if (styleRight != STYLE_NONE_CONST && dashPatternRight != dashPatternBottom)
+ {
+ cb.Stroke();
+ cb.SetLineDash(dashPatternRight, 0);
+ if (hideCorners && styleBottom == STYLE_NONE_CONST && radioBR == 0)
+ {
+ cb.MoveTo(x + w, y + penAux);
+ }
+ else
+ {
+ cb.MoveTo(x + w, y + radioBR);
+ }
+ }
+
+ //-------------------top right corner---------------------
+ if (styleRight != STYLE_NONE_CONST)
+ {
+ if (hideCorners && styleTop == STYLE_NONE_CONST && radioTR == 0)
+ {
+ cb.LineTo(x + w, y + h - penAux);
+ }
+ else
+ {
+ cb.LineTo(x + w, y + h - radioTR);
+ }
+ if (radioTR > 0 && styleTop != STYLE_NONE_CONST)
+ {
+ cb.CurveTo(x + w, y + h - radioTR * b, x + w - radioTR * b, y + h, x + w - radioTR, y + h);
+ }
+ }
+
+ //-------------------top line---------------------
+
+ if (styleTop != STYLE_NONE_CONST && dashPatternTop != dashPatternRight)
+ {
+ cb.Stroke();
+ cb.SetLineDash(dashPatternTop, 0);
+ if (hideCorners && styleRight == STYLE_NONE_CONST && radioTR == 0)
+ {
+ cb.MoveTo(x + w - penAux, y + h);
+ }
+ else
+ {
+ cb.MoveTo(x + w - radioTR, y + h);
+ }
+ }
+
+ //-------------------top left corner---------------------
+ if (styleTop != STYLE_NONE_CONST)
+ {
+ if (hideCorners && styleLeft == STYLE_NONE_CONST && radioTL == 0)
+ {
+ cb.LineTo(x + penAux, y + h);
+ }
+ else
+ {
+ cb.LineTo(x + radioTL, y + h);
+ }
+ if (radioTL > 0 && styleLeft != STYLE_NONE_CONST)
+ {
+ cb.CurveTo(x + radioTL * b, y + h, x, y + h - radioTL * b, x, y + h - radioTL);
+ }
+ }
+
+ //-------------------left line---------------------
+
+ if (styleLeft != STYLE_NONE_CONST && dashPatternLeft != dashPatternTop)
+ {
+ cb.Stroke();
+ cb.SetLineDash(dashPatternLeft, 0);
+ if (hideCorners && styleTop == STYLE_NONE_CONST && radioTL == 0)
+ {
+ cb.MoveTo(x, y + h - penAux);
+ }
+ else
+ {
+ cb.MoveTo(x, y + h - radioTL);
+ }
+ }
+
+ //-------------------bottom left corner---------------------
+ if (styleLeft != STYLE_NONE_CONST)
+ {
+ if (hideCorners && styleBottom == STYLE_NONE_CONST && radioBL == 0)
+ {
+ cb.LineTo(x, y + penAux);
+ }
+ else
+ {
+ cb.LineTo(x, y + radioBL);
+ }
+ if (radioBL > 0 && styleBottom != STYLE_NONE_CONST)
+ {
+ cb.CurveTo(x, y + radioBL * b, x + radioBL * b, y, x + radioBL, y);
+ }
+ }
+ cb.Stroke();
+
+ }
+
+ private void roundRectangle(PdfCanvas cb, float x, float y, float w, float h, float radioTL, float radioTR, float radioBL, float radioBR)
+ {
+ //-------------------bottom line---------------------
+
+
+ float b = 0.4477f;
+ if (radioBL > 0)
+ {
+ cb.MoveTo(x + radioBL, y);
+ }
+ else
+ {
+ cb.MoveTo(x, y);
+ }
+
+ //-------------------bottom right corner---------------------
+
+ cb.LineTo(x + w - radioBR, y);
+ if (radioBR > 0)
+ {
+ cb.CurveTo(x + w - radioBR * b, y, x + w, y + radioBR * b, x + w, y + radioBR);
+ }
+
+
+ cb.LineTo(x + w, y + h - radioTR);
+ if (radioTR > 0)
+ {
+ cb.CurveTo(x + w, y + h - radioTR * b, x + w - radioTR * b, y + h, x + w - radioTR, y + h);
+ }
+
+ cb.LineTo(x + radioTL, y + h);
+ if (radioTL > 0)
+ {
+ cb.CurveTo(x + radioTL * b, y + h, x, y + h - radioTL * b, x, y + h - radioTL);
+ }
+ cb.LineTo(x, y + radioBL);
+ if (radioBL > 0)
+ {
+ cb.CurveTo(x, y + radioBL * b, x + radioBL * b, y, x + radioBL, y);
+ }
+ }
+
+ public override void GxDrawRect(int left, int top, int right, int bottom, int pen, int foreRed, int foreGreen, int foreBlue, int backMode, int backRed, int backGreen, int backBlue,
+ int styleTop, int styleBottom, int styleRight, int styleLeft, int cornerRadioTL, int cornerRadioTR, int cornerRadioBL, int cornerRadioBR)
+ {
+ Color rectBackColor = new DeviceRgb(backRed, backGreen, backBlue);
+ Color rectForeColor = new DeviceRgb(foreRed, foreGreen, foreBlue);
+ GxDrawRect(left, top, right, bottom, pen, rectForeColor, backMode, rectBackColor, styleTop, styleBottom, styleRight, styleLeft, cornerRadioTL, cornerRadioTR, cornerRadioBL, cornerRadioBR);
+ }
+
+ void GxDrawRect(int left, int top, int right, int bottom, int pen, Color foreColor, int backMode, Color backColor,
+ int styleTop, int styleBottom, int styleRight, int styleLeft, int cornerRadioTL, int cornerRadioTR, int cornerRadioBL, int cornerRadioBR)
+ {
+ PdfCanvas cb = new PdfCanvas(pdfPage);
+
+ float penAux = (float)convertScale(pen);
+ float rightAux = (float)convertScale(right);
+ float bottomAux = (float)convertScale(bottom);
+ float leftAux = (float)convertScale(left);
+ float topAux = (float)convertScale(top);
+
+ GXLogging.Debug(log, "GxDrawRect -> (" + left + "," + top + ") - (" + right + "," + bottom + ") BackMode: " + backMode + " Pen:" + pen + ",leftMargin:" + leftMargin);
+ cb.SaveState();
+
+ float x1, y1, x2, y2;
+ x1 = leftAux + leftMargin;
+ y1 = pageSize.GetTop() - bottomAux - topMargin - bottomMargin;
+ x2 = rightAux + leftMargin;
+ y2 = pageSize.GetTop() - topAux - topMargin - bottomMargin;
+
+ cb.SetLineWidth(penAux);
+ cb.SetLineCapStyle(PdfCanvasConstants.LineCapStyle.PROJECTING_SQUARE);
+
+ if (cornerRadioBL == 0 && cornerRadioBR == 0 && cornerRadioTL == 0 && cornerRadioTR == 0 && styleBottom == 0 && styleLeft == 0 && styleRight == 0 && styleTop == 0)
+ {
+ //border color must be the same as the fill if border=0 since setLineWidth does not work.
+ if (pen > 0)
+ cb.SetStrokeColor(foreColor);
+ else
+ cb.SetStrokeColor(backColor);
+ cb.Rectangle(x1, y1, x2 - x1, y2 - y1);
+
+ if (backMode != 0)
+ {
+ cb.SetFillColor(backColor);
+ cb.FillStroke();
+ }
+
+ cb.ClosePathStroke();
+ }
+ else
+ {
+ float w = x2 - x1;
+ float h = y2 - y1;
+ if (w < 0)
+ {
+ x1 += w;
+ w = -w;
+ }
+ if (h < 0)
+ {
+ y1 += h;
+ h = -h;
+ }
+
+ float cRadioTL = (float)convertScale(cornerRadioTL);
+ float cRadioTR = (float)convertScale(cornerRadioTR);
+ float cRadioBL = (float)convertScale(cornerRadioBL);
+ float cRadioBR = (float)convertScale(cornerRadioBR);
+
+ // Scale the radius if it's too large or to small to fit.
+ int max = (int)Math.Min(w, h);
+ cRadioTL = Math.Max(0, Math.Min(cRadioTL, max / 2));
+ cRadioTR = Math.Max(0, Math.Min(cRadioTR, max / 2));
+ cRadioBL = Math.Max(0, Math.Min(cRadioBL, max / 2));
+ cRadioBR = Math.Max(0, Math.Min(cRadioBR, max / 2));
+
+ if (backMode != 0)
+ {
+ cb.SetStrokeColor(backColor);
+ cb.SetLineWidth(0);
+ roundRectangle(cb, x1, y1, w, h, cRadioTL, cRadioTR, cRadioBL, cRadioBR);
+ cb.SetFillColor(backColor);
+ cb.FillStroke();
+ cb.SetLineWidth(penAux);
+ }
+ if (pen > 0)
+ {
+ //Rectangle edge
+ cb.SetFillColor(backColor);
+ cb.SetStrokeColor(foreColor);
+ drawRectangle(cb, x1, y1, w, h,
+ styleTop, styleBottom, styleRight, styleLeft,
+ cRadioTL, cRadioTR,
+ cRadioBL, cRadioBR, penAux, false);
+ }
+ }
+ cb.RestoreState();
+ }
+ public override void GxDrawLine(int left, int top, int right, int bottom, int width, int foreRed, int foreGreen, int foreBlue, int style)
+ {
+ PdfCanvas cb = new PdfCanvas(pdfPage);
+
+ Color foreColor = new DeviceRgb(foreRed, foreGreen, foreBlue);
+
+ float widthAux = (float)convertScale(width);
+ float rightAux = (float)convertScale(right);
+ float bottomAux = (float)convertScale(bottom);
+ float leftAux = (float)convertScale(left);
+ float topAux = (float)convertScale(top);
+
+ GXLogging.Debug(log, "GxDrawLine leftAux: " + leftAux + ",leftMargin:" + leftMargin + ",pageSize.Top:" + pageSize.GetTop() + ",bottomAux:" + bottomAux + ",topMargin:" + topMargin + ",bottomMargin:" + bottomMargin);
+
+ GXLogging.Debug(log, "GxDrawLine -> (" + left + "," + top + ") - (" + right + "," + bottom + ") Width: " + width);
+ float x1, y1, x2, y2;
+ x1 = leftAux + leftMargin;
+ y1 = pageSize.GetTop() - bottomAux - topMargin - bottomMargin;
+ x2 = rightAux + leftMargin;
+ y2 = pageSize.GetTop() - topAux - topMargin - bottomMargin;
+
+ GXLogging.Debug(log, "Line-> (" + (x1) + "," + y1 + ") - (" + x2 + "," + y2 + ") ");
+ cb.SaveState();
+ cb.SetStrokeColor(foreColor);
+ cb.SetLineWidth(widthAux);
+
+ if (lineCapProjectingSquare)
+ {
+ cb.SetLineCapStyle(PdfCanvasConstants.LineCapStyle.PROJECTING_SQUARE);
+ }
+ if (style != 0)
+ {
+ float[] dashPattern = getDashedPattern(style);
+ cb.SetLineDash(dashPattern, 0);
+ }
+
+ cb.MoveTo(x1, y1);
+ cb.LineTo(x2, y2);
+ cb.Stroke();
+
+ cb.RestoreState();
+ }
+
+ public override void GxDrawBitMap(String bitmap, int left, int top, int right, int bottom, int aspectRatio)
+ {
+ try
+ {
+ Image image;
+ Image imageRef;
+ if (documentImages != null && documentImages.TryGetValue(bitmap, out imageRef))
+ {
+ image = imageRef;
+ }
+ else
+ {
+ try
+ {
+ if (!Path.IsPathRooted(bitmap))
+ {
+
+ image = new Image(ImageDataFactory.Create(defaultRelativePrepend + bitmap));
+ if (image == null)
+ {
+ bitmap = webAppDir + bitmap;
+ image = new Image(ImageDataFactory.Create(bitmap));
+ }
+ else
+ {
+ bitmap = defaultRelativePrepend + bitmap;
+ }
+ }
+ else
+ {
+ image = new Image(ImageDataFactory.Create(bitmap));
+ }
+ }
+ catch (Exception)//absolute url
+ {
+ Uri uri = new Uri(bitmap);
+ image = new Image(ImageDataFactory.Create(uri));
+ }
+ if (documentImages == null)
+ {
+ documentImages = new Dictionary();
+ }
+ documentImages[bitmap] = image;
+ }
+ GXLogging.Debug(log, "GxDrawBitMap -> '" + bitmap + "' [" + left + "," + top + "] - Size: (" + (right - left) + "," + (bottom - top) + ")");
+
+ if (image != null)
+ {
+ float rightAux = (float)convertScale(right);
+ float bottomAux = (float)convertScale(bottom);
+ float leftAux = (float)convertScale(left);
+ float topAux = (float)convertScale(top);
+ image.SetFixedPosition(this.getPage(),leftAux + leftMargin, this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin);
+ if (aspectRatio == 0)
+ image.ScaleAbsolute(rightAux - leftAux, bottomAux - topAux);
+ else
+ image.ScaleToFit(rightAux - leftAux, bottomAux - topAux);
+ image.GetAccessibilityProperties().SetAlternateDescription(Path.GetFileName(bitmap));
+ document.Add(image);
+ }
+ }
+ catch (PdfException de)
+ {
+ GXLogging.Error(log, "GxDrawBitMap document error", de);
+ }
+ catch (IOException ioe)
+ {
+ GXLogging.Error(log, "GxDrawBitMap io error", ioe);
+ }
+ catch (Exception e)
+ {
+ GXLogging.Error(log, "GxDrawBitMap error", e);
+ }
+ }
+
+ public override void GxAttris(String fontName, int fontSize, bool fontBold, bool fontItalic, bool fontUnderline, bool fontStrikethru, int Pen, int foreRed, int foreGreen, int foreBlue, int backMode, int backRed, int backGreen, int backBlue)
+ {
+ fontStyle = null;
+ bool _isCJK = false;
+ bool embeedFont = IsEmbeddedFont(fontName);
+ if (!embeedFont)
+ {
+ fontName = getSubstitute(fontName);
+ }
+
+ GXLogging.Debug(log, "GxAttris: ");
+ GXLogging.Debug(log, "\\-> Font: " + fontName + " (" + fontSize + ")" + (fontBold ? " BOLD" : "") + (fontItalic ? " ITALIC" : "") + (fontStrikethru ? " Strike" : ""));
+ GXLogging.Debug(log, "\\-> Fore (" + foreRed + ", " + foreGreen + ", " + foreBlue + ")");
+ GXLogging.Debug(log, "\\-> Back (" + backRed + ", " + backGreen + ", " + backBlue + ")");
+
+ if (barcode128AsImage && fontName.ToLower().IndexOf("barcode 128") >= 0 || fontName.ToLower().IndexOf("barcode128") >= 0)
+ {
+ barcode = new Barcode128(pdfDocument);
+ barcode.SetCodeType(Barcode128.CODE128);
+ }
+ else
+ {
+ barcode = null;
+ }
+ this.fontUnderline = fontUnderline;
+ this.fontStrikethru = fontStrikethru;
+ this.fontSize = fontSize;
+ this.fontBold = fontBold;
+ this.fontItalic = fontItalic;
+ foreColor = new DeviceRgb(foreRed, foreGreen, foreBlue);
+ backColor = new DeviceRgb(backRed, backGreen, backBlue);
+
+ backFill = (backMode != 0);
+ try
+ {
+ //LoadAsianFontsDll();
+ string f = fontName.ToLower();
+ if (PDFFont.isType1(fontName))
+ {
+ //Asian font
+ for (int i = 0; i < Type1FontMetrics.CJKNames.Length; i++)
+ {
+ if (Type1FontMetrics.CJKNames[i][0].ToLower().Equals(f) ||
+ Type1FontMetrics.CJKNames[i][1].ToLower().Equals(f))
+ {
+ fontStyle = new Style();
+ if (fontItalic) fontStyle.SetItalic();
+ if (fontBold) fontStyle.SetBold();
+
+ setAsianFont(fontName, string.Empty);
+ fontStyle.SetFont(baseFont);
+
+ _isCJK = true;
+ break;
+ }
+ }
+ if (!_isCJK)
+ {
+ int style = 0;
+ if (fontBold && fontItalic)
+ style = style + 3;
+ else
+ {
+ if (fontItalic)
+ style = style + 2;
+ if (fontBold)
+ style = style + 1;
+ }
+ for (int i = 0; i < PDFFont.base14.Length; i++)
+ {
+ if (PDFFont.base14[i][0].ToLower().Equals(f))
+ {
+ fontName = PDFFont.base14[i][1 + style].Substring(1);
+ break;
+ }
+ }
+ baseFont = PdfFontFactory.CreateFont(fontName, PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ }
+ }
+ else
+ {//True type font
+
+ if (IsEmbeddedFont(fontName))
+ {
+ fontStyle = new Style();
+ if (fontItalic) fontStyle.SetItalic();
+ if (fontBold) fontStyle.SetBold();
+ }
+ string fontPath = GetFontLocation(fontName);
+ bool foundFont = true;
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ MSPDFFontDescriptor fontDescriptor = new MSPDFFontDescriptor();
+ fontPath = fontDescriptor.getTrueTypeFontLocation(fontName);
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ baseFont = CreateDefaultFont();
+ foundFont = false;
+ }
+ else
+ {
+ props.setProperty(Const.MS_FONT_LOCATION, fontName, fontPath);
+ }
+ }
+ if (foundFont)
+ {
+ if (IsEmbeddedFont(fontName))
+ {
+ try
+ {
+ baseFont = PdfFontFactory.CreateFont(fontPath, PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
+ GXLogging.Debug(log, "EMBEED_SECTION Font");
+ }
+ catch (IOException ioEx)
+ {
+ Exception exDetailed = new Exception($"Error creating {fontPath}. Check font is installed for the current user", ioEx);
+ throw exDetailed;
+ }
+ }
+ else
+ {
+
+ fontStyle = new Style();
+ if (fontItalic) fontStyle.SetItalic();
+ if (fontBold) fontStyle.SetBold();
+
+ GXLogging.Debug(log, "NOT EMBEED_SECTION Font");
+
+ baseFont = PdfFontFactory.CreateFont(fontPath, PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ fontStyle.SetFont(baseFont);
+ }
+ }
+ else
+ {
+ GXLogging.Debug(log, "NOT foundFont fontName:" + fontName);
+ }
+ }
+ }
+ catch (PdfException de)
+ {
+ GXLogging.Debug(log, "GxAttris DocumentException", de);
+ throw de;
+ }
+ catch (Exception e)
+ {
+ GXLogging.Debug(log, "GxAttris error", e);
+ baseFont = CreateDefaultFont();
+ }
+ }
+
+ private PdfFont CreateDefaultFont()
+ {
+ if (defaultFont == null)
+ {
+ if (IsPdfA())
+ defaultFont = PdfFontFactory.CreateFont("Helvetica", PdfEncodings.CP1252, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ else
+ defaultFont = PdfFontFactory.CreateFont("Helvetica", PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ }
+ return PdfFontFactory.CreateFont("Helvetica", PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ }
+
+ public override void setAsianFont(String fontName, String style)
+ {
+ //LoadAsianFontsDll();
+ try
+ {
+ if (fontName.Equals("Japanese"))
+ baseFont = PdfFontFactory.CreateFont("HeiseiMin-W3", "UniJIS-UCS2-H", PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ if (fontName.Equals("Japanese2"))
+ baseFont = PdfFontFactory.CreateFont("HeiseiKakuGo-W5", "UniJIS-UCS2-H", PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ if (fontName.Equals("SimplifiedChinese"))
+ baseFont = PdfFontFactory.CreateFont("STSong-Light", "UniGB-UCS2-H", PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ if (fontName.Equals("TraditionalChinese"))
+ baseFont = PdfFontFactory.CreateFont("MHei-Medium", "UniCNS-UCS2-H", PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ if (fontName.Equals("Korean"))
+ baseFont = PdfFontFactory.CreateFont("HYSMyeongJo-Medium", "UniKS-UCS2-H", PdfFontFactory.EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ }
+ catch (PdfException de)
+ {
+ GXLogging.Debug(log, "setAsianFont error", de);
+ }
+ catch (IOException ioe)
+ {
+ GXLogging.Debug(log, "setAsianFont io error", ioe);
+ }
+ }
+
+ public override void GxDrawText(String sTxt, int left, int top, int right, int bottom, int align, int htmlformat, int border, int valign)
+ {
+ GXLogging.Debug(log, "GxDrawText, text:" + sTxt);
+
+ bool printRectangle = false;
+ if (props.getBooleanGeneralProperty(Const.BACK_FILL_IN_CONTROLS, true))
+ printRectangle = true;
+
+ if (printRectangle && (border == 1 || backFill))
+ GxDrawRect(left, top, right, bottom, border, foreColor, backFill ? 1 : 0, backColor, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ PdfCanvas canvas = new PdfCanvas(pdfPage);
+ sTxt = sTxt.TrimEnd(TRIM_CHARS);
+
+ PdfFont font = baseFont;
+ canvas.SetFontAndSize(this.baseFont, fontSize);
+ canvas.SetFillColor(foreColor);
+ float captionHeight = baseFont.GetAscent(sTxt, fontSize) / 1000;
+ float rectangleWidth = baseFont.GetWidth(sTxt, fontSize);
+ float lineHeight = (1 / 1000) * (baseFont.GetAscent(sTxt, fontSize) - baseFont.GetDescent(sTxt, fontSize)) + (fontSize * 1.2f);
+ float textBlockHeight = (float)convertScale(bottom - top);
+ int linesCount = (int)(textBlockHeight / lineHeight);
+ int bottomOri = bottom;
+ int topOri = top;
+
+ if (linesCount >= 2 && !((align & 16) == 16) && htmlformat != 1)
+ if (valign == (int)VerticalAlign.TOP)
+ bottom = top + (int)reconvertScale(lineHeight);
+ else if (valign == (int)VerticalAlign.BOTTOM)
+ top = bottom - (int)reconvertScale(lineHeight);
+
+ float bottomAux = (float)convertScale(bottom) - ((float)convertScale(bottom - top) - captionHeight) / 2;
+ float topAux = (float)convertScale(top) + ((float)convertScale(bottom - top) - captionHeight) / 2; ;
+
+ float leftAux = (float)convertScale(left);
+ float rightAux = (float)convertScale(right);
+ int alignment = align & 3;
+ bool autoResize = (align & 256) == 256;
+
+ GXLogging.Debug(log, "GxDrawText left: " + left + ",top:" + top + ",right:" + right + ",bottom:" + bottom + ",captionHeight:" + captionHeight + ",fontSize:" + fontSize);
+ GXLogging.Debug(log, "GxDrawText leftAux: " + leftAux + ",leftMargin:" + leftMargin + ",pageSize.Top:" + pageSize.GetTop() + ",bottomAux:" + bottomAux + ",topMargin:" + topMargin + ",bottomMargin:" + bottomMargin);
+ if (htmlformat == 1)
+ {
+ try
+ {
+ ConverterProperties converterProperties = new ConverterProperties();
+ FontProvider fontProvider = document.GetFontProvider();
+ if (IsTrueType(baseFont))
+ {
+ Hashtable locations = GetFontLocations();
+ foreach (string fontName in locations.Keys)
+ {
+ string fontPath = (string)locations[fontName];
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ MSPDFFontDescriptor fontDescriptor = new MSPDFFontDescriptor();
+ fontPath = fontDescriptor.getTrueTypeFontLocation(fontName);
+ }
+ if (!string.IsNullOrEmpty(fontPath))
+ {
+
+ fontProvider.AddFont(fontPath);
+ }
+ }
+ }
+ converterProperties.SetFontProvider(fontProvider);
+ bottomAux = (float)convertScale(bottom);
+ topAux = (float)convertScale(top);
+ float drawingPageHeight = this.pageSize.GetTop() - topMargin - bottomMargin;
+
+ float llx = leftAux + leftMargin;
+ float lly = drawingPageHeight - bottomAux;
+ float urx = rightAux + leftMargin;
+ float ury = drawingPageHeight - topAux;
+
+ Rectangle htmlRectangle = new Rectangle(llx, lly, urx - llx, ury - lly);
+ YPosition yPosition = new YPosition(htmlRectangle.GetTop());
+
+ Canvas htmlCanvas = new Canvas(canvas, htmlRectangle);
+ htmlCanvas.SetFontProvider(fontProvider);
+
+ //Iterate over the elements (a.k.a the parsed HTML string) and handle each case accordingly
+ IList elements = HtmlConverter.ConvertToElements(sTxt, converterProperties);
+ foreach (IElement element in elements)
+ {
+ float blockElementHeight = GetBlockElementHeight((IBlockElement)element, htmlRectangle);
+
+ if (PageHeightExceeded(bottomMargin, yPosition.CurrentYPosition))
+ {
+ llx = leftAux + leftMargin;
+ lly = drawingPageHeight - bottomAux;
+ urx = rightAux + leftMargin;
+ ury = drawingPageHeight - topAux;
+ htmlRectangle = new Rectangle(llx, lly, urx - llx, ury - lly);
+ yPosition = new YPosition(htmlRectangle.GetTop());
+ bottomAux -= drawingPageHeight;
+ GxEndPage();
+ GxStartPage();
+
+ canvas = new PdfCanvas(pdfPage);
+ sTxt = sTxt.TrimEnd(TRIM_CHARS);
+ canvas.SetFontAndSize(this.baseFont, fontSize);
+ canvas.SetFillColor(foreColor);
+
+ htmlCanvas = new Canvas(canvas, htmlRectangle);
+ htmlCanvas.SetFontProvider(fontProvider);
+ }
+ ProcessHTMLElement((IBlockElement)element, alignment, htmlCanvas);
+ yPosition.CurrentYPosition -= blockElementHeight;
+ }
+
+ }
+ catch (Exception ex1)
+ {
+ GXLogging.Debug(log, "Error adding html: ", ex1);
+ }
+
+ }
+ else if (barcode != null)
+ {
+ GXLogging.Debug(log, "Barcode" + barcode.GetType().ToString());
+ try
+ {
+ barcode.SetCode(sTxt);
+ barcode.SetTextAlignment(alignment);
+ Rectangle rectangle = new Rectangle(0, 0);
+
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ rectangle = rectangle.SetBbox((leftAux + rightAux) / 2 + leftMargin - rectangleWidth / 2,
+ (float)this.pageSize.GetTop() - (float)convertScale(bottom) - topMargin - bottomMargin,
+ (leftAux + rightAux) / 2 + leftMargin + rectangleWidth / 2,
+ (float)this.pageSize.GetTop() - (float)convertScale(top) - topMargin - bottomMargin);
+ break;
+ case 2: // Right Alignment
+ rectangle = rectangle.SetBbox(rightAux + leftMargin - rectangleWidth,
+ (float)this.pageSize.GetTop() - (float)convertScale(bottom) - topMargin - bottomMargin,
+ rightAux + leftMargin,
+ (float)this.pageSize.GetTop() - (float)convertScale(top) - topMargin - bottomMargin);
+ break;
+ case 0: // Left Alignment
+ rectangle = rectangle.SetBbox(leftAux + leftMargin,
+ (float)this.pageSize.GetTop() - (float)convertScale(bottom) - topMargin - bottomMargin,
+ leftAux + leftMargin + rectangleWidth,
+ (float)this.pageSize.GetTop() - (float)convertScale(top) - topMargin - bottomMargin);
+ break;
+ }
+ barcode.SetAltText(string.Empty);
+ barcode.SetBaseline(0);
+
+ if (fontSize < Const.LARGE_FONT_SIZE)
+ barcode.SetX(Const.OPTIMAL_MINIMU_BAR_WIDTH_SMALL_FONT);
+ else
+ barcode.SetX(Const.OPTIMAL_MINIMU_BAR_WIDTH_LARGE_FONT);
+
+
+ Image imageCode = new Image(barcode.CreateFormXObject(backFill ? backColor : null, foreColor, pdfDocument));
+ imageCode.SetFixedPosition(leftAux + leftMargin, rectangle.GetBottom());
+ barcode.SetBarHeight(rectangle.GetHeight());
+ imageCode.ScaleToFit(rectangle.GetWidth(), rectangle.GetHeight());
+ document.Add(imageCode);
+ }
+ catch (Exception ex)
+ {
+ GXLogging.Error(log, "Error generating Barcode " + barcode.GetType().ToString(), ex);
+ }
+ }
+ else
+ {
+
+ if (sTxt.Trim().ToLower().Equals("{{pages}}"))
+ {
+ GXLogging.Debug(log, "GxDrawText addTemplate-> (" + (leftAux + leftMargin) + "," + (this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin) + ") ");
+ templateRectangle = new Rectangle(leftAux + leftMargin, (float)this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin, rightAux + leftMargin, (float)this.pageSize.GetTop() - topAux - topMargin - bottomMargin);
+
+ templatex = leftAux + leftMargin;
+ templatey = this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin;
+ templateFont = this.baseFont;
+ templateFontSize = fontSize;
+ templateColorFill = foreColor;
+ templateAlignment = alignment;
+ templateCreated = true;
+ }
+
+ float textBlockWidth = rightAux - leftAux;
+ float TxtWidth = baseFont.GetWidth(sTxt, fontSize);
+ Boolean justified = (alignment == 3) && textBlockWidth < TxtWidth;
+ Boolean wrap = ((align & 16) == 16);
+
+ float leading = (float)Convert.ToDouble(props.getGeneralProperty(Const.LEADING), CultureInfo.InvariantCulture.NumberFormat);
+ Style style = new Style();
+ if (fontBold) style.SetBold();
+ if (fontItalic) style.SetItalic();
+ if (fontStrikethru) style.SetUnderline(fontSize / 6, fontSize / 2);
+ if (fontUnderline) style.SetUnderline(fontSize / 6, 0);
+ style.SetFont(font);
+ style.SetFontSize(fontSize);
+ style.SetFontColor(foreColor);
+
+ if (wrap || justified)
+ {
+ bottomAux = (float)convertScale(bottomOri);
+ topAux = (float)convertScale(topOri);
+
+ float llx = leftAux + leftMargin;
+ float lly = this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin;
+ float urx = rightAux + leftMargin;
+ float ury = this.pageSize.GetTop() - topAux - topMargin - bottomMargin;
+
+ DrawTextColumn(llx, lly, urx, ury, leading, sTxt, valign, alignment, style, wrap);
+ }
+ else
+ {
+ try
+ {
+ if (!autoResize)
+ {
+ String newsTxt = sTxt;
+ while (TxtWidth > textBlockWidth && (newsTxt.Length - 1 >= 0))
+ {
+ sTxt = newsTxt;
+ newsTxt = newsTxt.Substring(0, newsTxt.Length - 1);
+ TxtWidth = this.baseFont.GetWidth(newsTxt, fontSize);
+ }
+ }
+
+ Paragraph p = new Paragraph(sTxt);
+ p.AddStyle(style);
+
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ document.ShowTextAligned(p, ((leftAux + rightAux) / 2) + leftMargin, this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin, this.getPage(), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 0);
+ break;
+ case 2: // Right Alignment
+ document.ShowTextAligned(p, rightAux + leftMargin, this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin, this.getPage(), TextAlignment.RIGHT, VerticalAlignment.MIDDLE, 0);
+ break;
+ case 0: // Left Alignment
+ case 3: // Justified, only one text line
+ document.ShowTextAligned(p, leftAux + leftMargin, this.pageSize.GetTop() - bottomAux - topMargin - bottomMargin, this.getPage(), TextAlignment.LEFT, VerticalAlignment.MIDDLE, 0);
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ GXLogging.Error(log, "GxDrawText failed to draw simple text: ", e);
+ }
+ }
+ }
+ }
+
+ private void ProcessHTMLElement(IBlockElement blockElement, int alignment, Canvas htmlCanvas)
+ {
+ if (blockElement is Paragraph p)
+ {
+ if (alignment != 0)
+ p.SetTextAlignment(GetTextAlignment(alignment));
+ }
+ htmlCanvas.Add(blockElement);
+ }
+ bool PageHeightExceeded(float bottomAux, float drawingPageHeight)
+ {
+ return bottomAux > drawingPageHeight;
+ }
+ private float GetBlockElementHeight(IBlockElement blockElement, Rectangle htmlRectangle)
+ {
+ return blockElement.CreateRendererSubTree().SetParent(document.GetRenderer()).Layout(new LayoutContext(new LayoutArea(this.getPage(), htmlRectangle))).GetOccupiedArea().GetBBox().GetHeight();
+ }
+
+ //Utility class used to know where the cursor is left after each block element (HTML tag) is rendered
+ private class YPosition
+ {
+ public YPosition(float initialYPosition)
+ {
+ CurrentYPosition = initialYPosition;
+ }
+
+ public float CurrentYPosition { get; set; }
+ }
+
+ private BaseDirection? GetBaseDirection(int runDirection)
+ {
+ switch (runDirection)
+ {
+ case 2: return BaseDirection.LEFT_TO_RIGHT;
+ default: return null;
+ }
+ }
+
+ private VerticalAlignment GetVerticalAlignment(float valign)
+ {
+ if (valign == (int)VerticalAlign.TOP)
+ return VerticalAlignment.TOP;
+ else if (valign == (int)VerticalAlign.BOTTOM)
+ return VerticalAlignment.BOTTOM;
+ else
+ return VerticalAlignment.MIDDLE;
+ }
+
+ private TextAlignment? GetTextAlignment(int alignment)
+ {
+ switch (alignment)
+ {
+ case 1: return TextAlignment.CENTER;
+ case 2: return TextAlignment.RIGHT;
+ case 0: return TextAlignment.LEFT;
+ case 3: return TextAlignment.JUSTIFIED;
+ }
+ return null;
+ }
+
+ void DrawTextColumn(float llx, float lly, float urx, float ury, float leading, String text, int valign, int alignment, Style style, Boolean wrap)
+ {
+ Paragraph p = new Paragraph(text);
+
+ if (valign == (int)VerticalAlign.MIDDLE)
+ {
+ ury = ury + leading;
+ p.SetVerticalAlignment(VerticalAlignment.MIDDLE);
+ }
+ else if (valign == (int)VerticalAlign.BOTTOM)
+ {
+ ury = ury + leading;
+ p.SetVerticalAlignment(VerticalAlignment.BOTTOM);
+ }
+ else if (valign == (int)VerticalAlign.TOP)
+ {
+ ury = ury + leading / 2;
+ p.SetVerticalAlignment(VerticalAlignment.TOP);
+ }
+ Rectangle rect = new Rectangle(llx, lly, urx - llx, ury - lly);
+ p.SetTextAlignment(GetTextAlignment(alignment));
+ p.AddStyle(style);
+
+ if (wrap)
+ {
+ p.SetProperty(Property.SPLIT_CHARACTERS, new CustomSplitCharacters());
+ Table table = new Table(1);
+ table.SetFixedPosition(this.getPage(), rect.GetX(), rect.GetY(), rect.GetWidth());
+ Cell cell = new Cell();
+ cell.SetWidth(rect.GetWidth());
+ cell.SetHeight(rect.GetHeight());
+ cell.SetBorder(Border.NO_BORDER);
+ cell.SetVerticalAlignment(VerticalAlignment.MIDDLE);
+ cell.Add(p);
+ table.AddCell(cell);
+ document.Add(table);
+ }
+ else
+ {
+ try
+ {
+ PdfCanvas pdfCanvas = new PdfCanvas(pdfPage);
+ Canvas canvas = new Canvas(pdfCanvas, rect);
+ canvas.Add(p);
+ canvas.Close();
+ }
+ catch (Exception e) { GXLogging.Error(log, "GxDrawText failed to justify text column: ", e); }
+ }
+ }
+
+ public class CustomSplitCharacters : DefaultSplitCharacters
+ {
+ public override bool IsSplitCharacter(GlyphLine text, int glyphPos)
+ {
+ if (!text.Get(glyphPos).HasValidUnicode())
+ {
+ return false;
+ }
+
+ bool baseResult = base.IsSplitCharacter(text, glyphPos);
+ bool myResult = false;
+ Glyph glyph = text.Get(glyphPos);
+
+ if (glyph.GetUnicode() == '_')
+ {
+ myResult = true;
+ }
+ return myResult || baseResult;
+ }
+ }
+
+#pragma warning restore CS0612 // Type or member is obsolete
+
+ private PageSize ComputePageSize(float leftMargin, float topMargin, int width, int length, bool marginsInsideBorder)
+ {
+ if ((leftMargin == 0 && topMargin == 0) || marginsInsideBorder)
+ {
+ if (length == 23818 && width == 16834)
+ return PageSize.A3;
+ else if (length == 16834 && width == 11909)
+ return PageSize.A4;
+ else if (length == 11909 && width == 8395)
+ return PageSize.A5;
+ else if (length == 20016 && width == 5731)
+ return PageSize.B4;
+ else if (length == 14170 && width == 9979)
+ return PageSize.B5;
+ else if (length == 15120 && width == 10440)
+ return PageSize.EXECUTIVE;
+ else if (length == 20160 && width == 12240)
+ return PageSize.LEGAL;
+ else if (length == 15840 && width == 12240)
+ return PageSize.LETTER;
+ else
+ return new PageSize(new Rectangle((int)(width / PAGE_SCALE_X), (int)(length / PAGE_SCALE_Y)));
+ }
+ return new PageSize(new Rectangle((int)(width / PAGE_SCALE_X) + leftMargin, (int)(length / PAGE_SCALE_Y) + topMargin));
+ }
+ public override void GxEndDocument()
+ {
+ //{{Pages}}
+ if (templateCreated)
+ {
+ int totalPages = pdfDocument.GetNumberOfPages();
+ for (int i = 0; i < totalPages; i++)
+ {
+ PdfPage page = pdfDocument.GetPage(i);
+ Canvas canvas = new Canvas(page, templateRectangle);
+ canvas.ShowTextAligned(i.ToString(CultureInfo.InvariantCulture), templatex, templatey, TextAlignment.CENTER).SetBackgroundColor(templateColorFill).SetFont(templateFont).SetFontSize(templateFontSize);
+ }
+ }
+
+ int copies = 1;
+ try
+ {
+ copies = Convert.ToInt32(printerSettings.getProperty(form, Const.COPIES));
+ GXLogging.Debug(log, "Setting number of copies to " + copies);
+ PdfViewerPreferences preferences = new PdfViewerPreferences();
+ preferences.SetNumCopies(copies);
+
+ int duplex = Convert.ToInt32(printerSettings.getProperty(form, Const.DUPLEX));
+ PdfViewerPreferences.PdfViewerPreferencesConstants duplexValue;
+ if (duplex == 1)
+ duplexValue = PdfViewerPreferences.PdfViewerPreferencesConstants.SIMPLEX;
+ else if (duplex == 2)
+ duplexValue = PdfViewerPreferences.PdfViewerPreferencesConstants.DUPLEX_FLIP_LONG_EDGE;
+ else if (duplex == 3)
+ duplexValue = PdfViewerPreferences.PdfViewerPreferencesConstants.DUPLEX_FLIP_SHORT_EDGE;
+ else if (duplex == 4)
+ duplexValue = PdfViewerPreferences.PdfViewerPreferencesConstants.DUPLEX_FLIP_LONG_EDGE;
+ else
+ duplexValue = PdfViewerPreferences.PdfViewerPreferencesConstants.NONE;
+ GXLogging.Debug(log, "Setting duplex to " + duplexValue.ToString());
+ preferences.SetDuplex(duplexValue);
+ }
+ catch (Exception ex)
+ {
+ GXLogging.Error(log, "Setting viewer preference error", ex);
+ }
+
+ bool printingScript = false;
+ String serverPrinting = props.getGeneralProperty(Const.SERVER_PRINTING);
+ bool fit = props.getGeneralProperty(Const.ADJUST_TO_PAPER).Equals("true");
+ if ((outputType == Const.OUTPUT_PRINTER || outputType == Const.OUTPUT_STREAM_PRINTER) && serverPrinting.Equals("false"))
+ {
+
+ printingScript = true;
+ StringBuilder javascript = new StringBuilder(); ;
+
+ javascript.Append("var pp = this.getPrintParams();");
+ String printer = printerSettings.getProperty(form, Const.PRINTER).Replace("\\", "\\\\");
+ if (!string.IsNullOrEmpty(printer))
+ javascript.Append("pp.printerName = \"" + printer + "\";\n");
+
+ if (fit)
+ {
+ javascript.Append("pp.pageHandling = pp.constants.handling.fit;\n");
+ }
+ else
+ {
+ javascript.Append("pp.pageHandling = pp.constants.handling.none;\n");
+ }
+
+ GXLogging.Debug(log, "MODE:" + printerSettings.getProperty(form, Const.MODE) + ",form:" + form);
+
+ if (printerSettings.getProperty(form, Const.MODE, "3").StartsWith("0"))//Show printer dialog Never
+ {
+ javascript.Append("pp.interactive = pp.constants.interactionLevel.automatic;\n");
+
+ for (int i = 0; i < copies; i++)
+ {
+ javascript.Append("this.print(pp);\n");
+ }
+
+ //writer.addJavaScript("this.print({bUI: false, bSilent: true, bShrinkToFit: true});");
+ //No print dialog is displayed. During printing a progress monitor and cancel
+ //dialog is displayed and removed automatically when printing is complete.
+ }
+ else //Show printer dialog is sent directly to printer | always
+ {
+ javascript.Append("pp.interactive = pp.constants.interactionLevel.full;\n");
+ //Displays the print dialog allowing the user to change print settings and requiring
+ //the user to press OK to continue. During printing a progress monitor and cancel
+ //dialog is displayed and removed automatically when printing is complete.
+
+ javascript.Append("this.print(pp);\n");
+
+ }
+ pdfDocument.GetCatalog().SetOpenAction(PdfAction.CreateJavaScript(javascript.ToString()));
+ }
+
+ if (IsPdfA())
+ {
+ /*using (Stream iccProfile = ReadResource("sRGB Color Space Profile.icm"))
+ {
+ ICC_Profile icc = ICC_Profile.GetInstance(iccProfile);
+ writer.SetOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
+ }
+
+ writer.ExtraCatalog.Put(PdfName.LANG, new PdfString(Config.GetCultureForLang(language).Name));
+ PdfDictionary markInfo = new PdfDictionary(PdfName.MARKINFO);
+ markInfo.Put(PdfName.MARKED, new PdfBoolean(PdfBoolean.TRUE));
+ writer.ExtraCatalog.Put(PdfName.MARKINFO, markInfo);
+
+ writer.CreateXmpMetadata();*/
+
+ }
+ document.Close();
+ GXLogging.Debug(log, "GxEndDocument!");
+ try
+ {
+ props.save();
+ GXLogging.Debug(log, "props.save()");
+ }
+ catch (IOException e)
+ {
+ GXLogging.Error(log, "props.save() error", e);
+
+ }
+ GXLogging.Debug(log, "outputType: " + outputType + ",docName:" + docName);
+
+ switch (outputType)
+ {
+ case Const.OUTPUT_SCREEN:
+ try
+ {
+ outputStream.Close();
+ GXLogging.Debug(log, "GxEndDocument OUTPUT_SCREEN outputstream length" + outputStream.ToString().Length);
+ }
+ catch (IOException e)
+ {
+ GXLogging.Error(log, "GxEndDocument OUTPUT_SCREEN error", e);
+ }
+ try { showReport(docName, modal); }
+ catch (Exception){}
+ break;
+
+ case Const.OUTPUT_PRINTER:
+ try { outputStream.Close(); }
+ catch (IOException) {; } // Cierro el archivo
+ try
+ {
+ if (!serverPrinting.Equals("false") && !printingScript)
+ {
+ printReport(docName, this.printerOutputMode == 0, printerSettings.getProperty(form, Const.PRINTER));
+ }
+ }
+ catch (Exception){}
+ break;
+
+ case Const.OUTPUT_FILE:
+ try
+ {
+ outputStream.Close();
+ GXLogging.Debug(log, "GxEndDocument OUTPUT_FILE outputstream length" + outputStream.ToString().Length);
+ }
+ catch (IOException e)
+ {
+ GXLogging.Error(log, "GxEndDocument OUTPUT_FILE error", e);
+ }
+ break;
+
+ case Const.OUTPUT_STREAM:
+ case Const.OUTPUT_STREAM_PRINTER:
+ default: break;
+ }
+ outputStream = null;
+
+ GXLogging.Debug(log, "GxEndDocument End");
+ }
+ public override void GxStartPage()
+ {
+ try
+ {
+ pdfPage = pdfDocument.AddNewPage();
+ GXLogging.Debug(log, "GxStartPage pages:" + pages + ",new page:" + pages + 1);
+ pages = pages + 1;
+ }
+ catch (PdfException de)
+ {
+ GXLogging.Error(log, "GxStartPage error", de);
+ }
+ }
+
+ private bool IsTrueType(PdfFont font)
+ {
+ return font.GetFontProgram() is TrueTypeFont;
+ }
+ }
+}
+
diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs
new file mode 100644
index 000000000..0f1a30120
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxPdfReportsCS/PDFReportPDFPig.cs
@@ -0,0 +1,1044 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.Drawing.Text;
+using System.IO;
+using System.Net.Http;
+using System.Text;
+using GeneXus;
+using UglyToad.PdfPig.Core;
+using UglyToad.PdfPig.Fonts.Standard14Fonts;
+using UglyToad.PdfPig.Writer;
+using static GeneXus.Utils.StringUtil;
+using static UglyToad.PdfPig.Writer.PdfDocumentBuilder;
+using static UglyToad.PdfPig.Writer.PdfPageBuilder;
+using Color = System.Drawing.Color;
+using Font = System.Drawing.Font;
+using PageSize = UglyToad.PdfPig.Content.PageSize;
+using PdfRectangle = UglyToad.PdfPig.Core.PdfRectangle;
+
+namespace GeneXus.Printer
+{
+ public class GxReportBuilderPDFPig : GxReportBuilderPdf
+ {
+ static IGXLogger log = GXLoggerFactory.GetLogger();
+ public GxReportBuilderPDFPig() { }
+ public GxReportBuilderPDFPig(string appPath, Stream outputStream)
+ {
+ _appPath = appPath;
+ _pdfReport = new com.genexus.reports.PDFReportPDFPig(appPath);
+ if (outputStream != null)
+ {
+ _pdfReport.setOutputStream(outputStream);
+ GXLogging.Debug(log, "GxReportBuilderPdf outputStream: binaryWriter");
+ }
+ }
+ }
+
+}
+
+namespace com.genexus.reports
+{
+ public class PDFReportPDFPig : PDFReportBase
+ {
+ static IGXLogger log = GXLoggerFactory.GetLogger();
+
+ private PdfDocumentBuilder documentBuilder;
+ private PdfPageBuilder pageBuilder;
+ private ExtendedPageSize pageSize;
+
+ private AddedFont baseFont;
+ private string baseFontPath;
+ private string baseFontName;
+ private Color backColor, foreColor;
+
+ private string barcodeType = null;
+
+ private Dictionary documentImages;
+
+ protected override void init(ref int gxYPage, ref int gxXPage, int pageWidth, int pageLength)
+ {
+ try
+ {
+ pageSize = ComputePageSize(leftMargin, topMargin, pageWidth, pageLength, props.getBooleanGeneralProperty(Const.MARGINS_INSIDE_BORDER, Const.DEFAULT_MARGINS_INSIDE_BORDER));
+ documentBuilder = new PdfDocumentBuilder();
+
+ pageBuilder = pageSize.IsCustomPageSize() ? documentBuilder.AddPage(pageSize.Width, pageSize.Height) : documentBuilder.AddPage(pageSize.PageSize);
+
+ gxXPage = (int) pageBuilder.PageSize.TopRight.X;
+ if (props.getBooleanGeneralProperty(Const.FIX_SAC24437, true))
+ gxYPage = (int)(pageLength / GX_PAGE_SCALE_Y);
+ else
+ gxYPage = (int)(pageLength / GX_PAGE_SCALE_Y_OLD);
+
+ }
+ catch (Exception e)
+ {
+ GXLogging.Error(log, "GxPrintInit failed", e);
+ }
+ }
+
+ public PDFReportPDFPig(string appPath) : base(appPath)
+ {
+ documentBuilder = null;
+ documentImages = new Dictionary();
+ }
+
+ public override void GxStartPage()
+ {
+ try
+ {
+ if (pages > 0)
+ {
+ pageBuilder = pageSize.IsCustomPageSize() ? documentBuilder.AddPage(pageSize.Width, pageSize.Height) : documentBuilder.AddPage(pageSize.PageSize);
+ }
+ pages = pages + 1;
+ }
+ catch (Exception de)
+ {
+ GXLogging.Error(log, "GxStartPage error", de);
+ }
+ }
+
+ internal override bool SetComplainceLevel(PdfConformanceLevel level)
+ {
+ return false;
+ }
+
+ public override void GxDrawRect(int left, int top, int right, int bottom, int pen, int foreRed, int foreGreen, int foreBlue, int backMode, int backRed, int backGreen, int backBlue,
+ int styleTop, int styleBottom, int styleRight, int styleLeft, int cornerRadioTL, int cornerRadioTR, int cornerRadioBL, int cornerRadioBR)
+ {
+ float penAux = (float)convertScale(pen);
+ float rightAux = (float)convertScale(right);
+ float bottomAux = (float)convertScale(bottom);
+ float leftAux = (float)convertScale(left);
+ float topAux = (float)convertScale(top);
+
+ float x1, y1, x2, y2;
+ x1 = leftAux + leftMargin;
+ y1 = (float)pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin;
+ x2 = rightAux + leftMargin;
+ y2 = (float)pageBuilder.PageSize.TopRight.Y - topAux - topMargin - bottomMargin;
+
+ GXLogging.Info(log, "Corner styling and radio are not taken into consideration because the PDFPig " +
+ "API provides no way to render rounded rectangles or style them");
+
+ if (pen > 0)
+ pageBuilder.SetStrokeColor( (byte)foreRed, (byte)foreGreen, (byte)foreBlue);
+ else
+ pageBuilder.SetStrokeColor( (byte)backRed, (byte)backGreen, (byte)backBlue);
+
+ GXLogging.Info(log, "The PDFPig API provides no way of setting the line cap style");
+
+ if (backMode != 0)
+ {
+ pageBuilder.SetTextAndFillColor((byte)backRed, (byte)backGreen, (byte)backBlue);
+ pageBuilder.DrawRectangle(new PdfPoint(x1, y1), (decimal)(x2 - x1), (decimal)(y2 - y1), (decimal)penAux, true);
+ }
+ else
+ {
+ pageBuilder.DrawRectangle(new PdfPoint(x1, y1), (decimal)(x2 - x1), (decimal)(y2 - y1), (decimal) penAux, false);
+ }
+ pageBuilder.ResetColor();
+ }
+
+ public override void GxDrawLine(int left, int top, int right, int bottom, int width, int foreRed, int foreGreen, int foreBlue, int style)
+ {
+ try
+ {
+ float widthAux = (float)convertScale(width);
+ float rightAux = (float)convertScale(right);
+ float bottomAux = (float)convertScale(bottom);
+ float leftAux = (float)convertScale(left);
+ float topAux = (float)convertScale(top);
+
+ GXLogging.Debug(log, "GxDrawLine -> (" + left + "," + top + ") - (" + right + "," + bottom + ") Width: " + width);
+
+ float x1, y1, x2, y2;
+
+ x1 = leftAux + leftMargin;
+ y1 = (float)pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin;
+ x2 = rightAux + leftMargin;
+ y2 = (float)pageBuilder.PageSize.TopRight.Y - topAux - topMargin - bottomMargin;
+
+ pageBuilder.SetStrokeColor((byte)foreRed, (byte)foreGreen, (byte)foreBlue);
+
+ if (style != 0)
+ {
+ GXLogging.Info(log, "The PDFPig API provides no way of creating a dashed line");
+ float[] dashPattern = getDashedPattern(style);
+ }
+
+ pageBuilder.DrawLine(new PdfPoint(x1, y1), new PdfPoint(x2, y2), (decimal)widthAux);
+ pageBuilder.ResetColor();
+ }
+ catch (Exception e)
+ {
+ GXLogging.Error(log, "GxDrawLine error", e);
+ }
+ }
+
+ public override void GxDrawBitMap(string bitmap, int left, int top, int right, int bottom, int aspectRatio)
+ {
+ try
+ {
+ string imageType = Path.GetExtension(bitmap).Substring(1);
+
+ float rightAux = (float)convertScale(right);
+ float bottomAux = (float)convertScale(bottom);
+ float leftAux = (float)convertScale(left);
+ float topAux = (float)convertScale(top);
+
+ float llx = leftAux + leftMargin;
+ float lly = (float) pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin;
+ float width;
+ float height;
+ if (aspectRatio == 0)
+ {
+ width = rightAux - leftAux;
+ height = bottomAux - topAux;
+ }
+ else
+ {
+ width = (rightAux - leftAux) * aspectRatio;
+ height = (bottomAux - topAux) * aspectRatio;
+ }
+
+ PdfRectangle position = new PdfRectangle(llx, lly, llx + width, lly + height);
+
+ AddedImage image = null;
+ AddedImage imageRef;
+ if (documentImages != null && documentImages.TryGetValue(bitmap, out imageRef))
+ {
+ image = imageRef;
+ }
+ else
+ {
+ try
+ {
+ if (!Path.IsPathRooted(bitmap))
+ {
+
+ image = imageType == "jpeg" ? pageBuilder.AddJpeg(File.ReadAllBytes(defaultRelativePrepend + bitmap), position) : pageBuilder.AddPng(File.ReadAllBytes(defaultRelativePrepend + bitmap), position);
+ if (image == null)
+ {
+ bitmap = webAppDir + bitmap;
+ image = imageType == "jpeg" ? pageBuilder.AddJpeg(File.ReadAllBytes(bitmap), position) : pageBuilder.AddPng(File.ReadAllBytes(bitmap), position);
+ }
+ else
+ {
+ bitmap = defaultRelativePrepend + bitmap;
+ }
+ }
+ else
+ {
+ image = imageType == "jpeg" ? pageBuilder.AddJpeg(File.ReadAllBytes(bitmap), position) : pageBuilder.AddPng(File.ReadAllBytes(bitmap), position);
+ }
+ }
+ catch (Exception)
+ {
+ image = AddImageFromURL(bitmap, position);
+ }
+ if (image == null)
+ {
+ image = AddImageFromURL(bitmap, position);
+ }
+
+ if (documentImages == null)
+ {
+ documentImages = new Dictionary();
+ }
+ documentImages[bitmap] = image;
+ }
+ GXLogging.Debug(log, "GxDrawBitMap -> '" + bitmap + "' [" + left + "," + top + "] - Size: (" + (right - left) + "," + (bottom - top) + ")");
+ }
+ catch (Exception e)
+ {
+ GXLogging.Error(log, "GxDrawBitMap error", e);
+ }
+ }
+
+ private AddedImage AddImageFromURL(string url, PdfRectangle position)
+ {
+ AddedImage image = null;
+ using (HttpClient httpClient = new HttpClient())
+ {
+ byte[] imageBytes = httpClient.GetByteArrayAsync(url).Result;
+ try
+ {
+ image = pageBuilder.AddJpeg(imageBytes, position);
+ }
+ catch (Exception)
+ {
+ pageBuilder.AddPng(imageBytes, position);
+ }
+ }
+ if (image == null)
+ {
+ GXLogging.Error(log, "GxDrawBitMap : PDFPig only supports adding jpeg or png images to documents");
+ }
+ return image;
+ }
+
+ public override void GxAttris(string fontName, int fontSize, bool fontBold, bool fontItalic, bool fontUnderline, bool fontStrikethru, int pen, int foreRed, int foreGreen, int foreBlue, int backMode, int backRed, int backGreen, int backBlue)
+ {
+ bool isCJK = false;
+ bool embedFont = IsEmbeddedFont(fontName);
+ string originalFontName = fontName;
+ if (!embedFont)
+ {
+ fontName = getSubstitute(fontName);
+ }
+
+ string fontSubstitute = originalFontName != fontName ? $"Original Font: {originalFontName} Substitute" : "";
+
+ GXLogging.Debug(log, $"GxAttris: ");
+ GXLogging.Debug(log, $"\\-> Font: {fontName} ({fontSize})" +
+ (fontBold ? " BOLD" : "") +
+ (fontItalic ? " ITALIC" : "") +
+ (fontStrikethru ? " Strike" : ""));
+ GXLogging.Debug(log, $"\\-> Fore ({foreRed}, {foreGreen}, {foreBlue})");
+ GXLogging.Debug(log, $"\\-> Back ({backRed}, {backGreen}, {backBlue})");
+
+ this.fontUnderline = fontUnderline;
+ this.fontStrikethru = fontStrikethru;
+ this.fontSize = fontSize;
+ foreColor = Color.FromArgb(foreRed, foreGreen, foreBlue);
+ backColor = Color.FromArgb(backRed, backGreen, backBlue);
+
+ backFill = backMode != 0;
+
+ try
+ {
+ string fontNameLower = fontName.ToLower();
+ if (PDFFont.isType1(fontName))
+ {
+ foreach (string[] cjkName in Type1FontMetrics.CJKNames)
+ {
+ if (cjkName[0].ToLower().Equals(fontNameLower) || cjkName[1].ToLower().Equals(fontNameLower))
+ {
+ string style = fontBold && fontItalic ? "BoldItalic" : fontItalic ? "Italic" : fontBold ? "Bold" : "";
+ setAsianFont(fontName, style);
+ isCJK = true;
+ break;
+ }
+ }
+ if (!isCJK)
+ {
+ int style = (fontBold && fontItalic ? 3 : 0) + (fontItalic && !fontBold ? 2 : 0) + (fontBold && !fontItalic ? 1 : 0);
+ foreach (string[] base14Font in PDFFont.base14)
+ {
+ if (base14Font[0].ToLower().Equals(fontNameLower))
+ {
+ fontName = base14Font[1 + style].Substring(1);
+ break;
+ }
+ }
+ ProcessBaseFont(fontName);
+ }
+ }
+ else
+ {
+ string style = (fontBold && fontItalic ? ",BoldItalic" : "") + (fontItalic && !fontBold ? ",Italic" : "") + (fontBold && !fontItalic ? ",Bold" : "");
+ fontName += style;
+ ProcessBaseFont(fontName);
+ }
+
+ if (barcode128AsImage && (
+ fontName.ToLower().Contains("barcode 128") || fontName.ToLower().Contains("barcode128")
+ ||
+ (!string.IsNullOrEmpty(baseFontPath) && (baseFontPath.ToLower().Contains("3of9") || baseFontPath.ToLower().Contains("3 of 9")))
+ )
+ )
+ {
+ barcodeType = "barcode128";
+ }
+ }
+ catch (Exception e)
+ {
+ GXLogging.Debug(log, "GxAttris DocumentException", e);
+ throw;
+ }
+ }
+
+ private void ProcessBaseFont(string fontName)
+ {
+ string fontLocation = GetFontLocation(fontName);
+ if (string.IsNullOrEmpty(fontLocation))
+ {
+ fontLocation = new MSPDFFontDescriptor().getTrueTypeFontLocation(fontName);
+ }
+
+ if (!string.IsNullOrEmpty(fontLocation))
+ {
+ byte[] fontBytes = File.ReadAllBytes(fontLocation);
+ baseFont = documentBuilder.AddTrueTypeFont(fontBytes);
+ }
+ else
+ {
+ baseFont = createType1FontFromName(fontName);
+ if (baseFont == null)
+ baseFont = documentBuilder.AddStandard14Font(Standard14Font.TimesRoman);
+ }
+
+ baseFontName = fontName;
+ baseFontPath = fontLocation;
+ }
+
+ private AddedFont createType1FontFromName(string fontName)
+ {
+ switch (fontName.ToLower())
+ {
+ case "times-roman":
+ return documentBuilder.AddStandard14Font(Standard14Font.TimesRoman);
+ case "times-bold":
+ return documentBuilder.AddStandard14Font(Standard14Font.TimesBold);
+ case "times-italic":
+ return documentBuilder.AddStandard14Font(Standard14Font.TimesItalic);
+ case "times-bolditalic":
+ return documentBuilder.AddStandard14Font(Standard14Font.TimesBoldItalic);
+ case "helvetica":
+ return documentBuilder.AddStandard14Font(Standard14Font.Helvetica);
+ case "helvetica-bold":
+ return documentBuilder.AddStandard14Font(Standard14Font.HelveticaBold);
+ case "helvetica-oblique":
+ return documentBuilder.AddStandard14Font(Standard14Font.HelveticaOblique);
+ case "helvetica-boldoblique":
+ return documentBuilder.AddStandard14Font(Standard14Font.HelveticaBoldOblique);
+ case "courier":
+ return documentBuilder.AddStandard14Font(Standard14Font.Courier);
+ case "courier-bold":
+ return documentBuilder.AddStandard14Font(Standard14Font.CourierBold);
+ case "courier-oblique":
+ return documentBuilder.AddStandard14Font(Standard14Font.CourierOblique);
+ case "courier-boldoblique":
+ return documentBuilder.AddStandard14Font(Standard14Font.CourierBoldOblique);
+ case "symbol":
+ return documentBuilder.AddStandard14Font(Standard14Font.Symbol);
+ case "zapfdingbats":
+ return documentBuilder.AddStandard14Font(Standard14Font.ZapfDingbats);
+ default:
+ return null;
+ }
+ }
+
+ public override void setAsianFont(string fontName, string style)
+ {
+ try
+ {
+ string fontPath = GetFontLocation(fontName);
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ MSPDFFontDescriptor fontDescriptor = new MSPDFFontDescriptor();
+ fontPath = fontDescriptor.getTrueTypeFontLocation(fontName);
+ }
+ byte[] fontBytes = File.ReadAllBytes(fontPath);
+ baseFont = documentBuilder.AddTrueTypeFont(fontBytes);
+ }
+ catch (IOException de)
+ {
+ GXLogging.Debug(log, "setAsianFont error", de);
+ }
+ }
+
+ public override void GxDrawText(string sTxt, int left, int top, int right, int bottom, int align, int htmlformat, int border, int valign)
+ {
+ bool printRectangle = false;
+ if (props.getBooleanGeneralProperty(Const.BACK_FILL_IN_CONTROLS, true))
+ printRectangle = true;
+
+ if (printRectangle && (border == 1 || backFill))
+ {
+ GxDrawRect(left, top, right, bottom, border, foreColor.R, foreColor.G, foreColor.B, backFill ? 1 : 0, backColor.R, backColor.G, backColor.B, 0, 0);
+ }
+
+ sTxt = RTrim(sTxt);
+
+ AddedFont font = createType1FontFromName(baseFontName);
+ if (font == null)
+ {
+ try
+ {
+ byte[] fontBytes = File.ReadAllBytes(baseFontPath);
+ font = documentBuilder.AddTrueTypeFont(fontBytes);
+ }
+ catch
+ {
+ font = baseFont;
+ }
+ }
+
+ float captionHeight = CalculateFontCaptionHeight(baseFontPath, fontSize);
+ float rectangleWidth = MeasureTextWidth(sTxt, baseFontPath, fontSize);
+ float lineHeight = MeasureTextHeight(sTxt, baseFontPath, fontSize);
+ float textBlockHeight = (float)convertScale(bottom - top);
+ int linesCount = (int)(textBlockHeight / lineHeight);
+ int bottomOri = bottom;
+ int topOri = top;
+
+ if (linesCount >= 2 && !((align & 16) == 16) && htmlformat != 1)
+ {
+ if (valign == (int)VerticalAlign.TOP)
+ bottom = top + (int)reconvertScale(lineHeight);
+ else if (valign == (int)VerticalAlign.BOTTOM)
+ top = bottom - (int)reconvertScale(lineHeight);
+ }
+
+ float bottomAux = (float)convertScale(bottom) - ((float)convertScale(bottom - top)) / 2;
+ float topAux = (float)convertScale(top) + ((float)convertScale(bottom - top)) / 2;
+
+ float startHeight = bottomAux - topAux - captionHeight;
+
+ float leftAux = (float)convertScale(left);
+ float rightAux = (float)convertScale(right);
+ int alignment = align & 3;
+ bool autoResize = (align & 256) == 256;
+
+ if (htmlformat == 1)
+ {
+ GXLogging.Error(log, "GxDrawText: PDFPig report implementation does not support rendering HTML content into PDF reports");
+ }
+
+ if (barcodeType != null)
+ {
+ PdfRectangle barcodeRectangle;
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ barcodeRectangle = new PdfRectangle(
+ (leftAux + rightAux) / 2 + leftMargin - rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - (float)convertScale(bottom) - topMargin - bottomMargin,
+ (leftAux + rightAux) / 2 + leftMargin + rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - (float)convertScale(top) - topMargin - bottomMargin
+ );
+ break;
+ case 2: // Right Alignment
+ barcodeRectangle = new PdfRectangle(
+ rightAux + leftMargin - rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - (float)convertScale(bottom) - topMargin - bottomMargin,
+ rightAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - (float)convertScale(top) - topMargin - bottomMargin
+ );
+ break;
+ default: // Left Alignment (Corresponds to alignment = 0 but used as default)
+ barcodeRectangle = new PdfRectangle(
+ leftAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - (float)convertScale(bottom) - topMargin - bottomMargin,
+ leftAux + leftMargin + rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - (float)convertScale(top) - topMargin - bottomMargin
+ );
+ break;
+
+ }
+ Image barcodeImage = CreateBarcodeImage((float)barcodeRectangle.Width, (float)barcodeRectangle.Height, baseFontPath, sTxt);
+ using (MemoryStream ms = new MemoryStream())
+ {
+ barcodeImage.Save(ms, ImageFormat.Png);
+ pageBuilder.AddPng(ms.ToArray(), barcodeRectangle);
+ }
+ return;
+ }
+
+ if (backFill)
+ {
+ PdfPoint rectangleStartingPoint;
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ rectangleStartingPoint = new PdfPoint(
+ (leftAux + rightAux) / 2 + leftMargin - rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin
+ );
+ break;
+ case 2: // Right Alignment
+ rectangleStartingPoint = new PdfPoint(
+ rightAux + leftMargin - rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin
+ );
+ break;
+ default: // Left Alignment (Corresponds to alignment = 0 but used as default)
+ rectangleStartingPoint = new PdfPoint(
+ leftAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin
+ );
+ break;
+
+ }
+
+ decimal width = (decimal)(((leftAux + rightAux) / 2 + leftMargin + rectangleWidth / 2) - ((leftAux + rightAux) / 2 + leftMargin - rectangleWidth / 2));
+ decimal height = (decimal)((pageBuilder.PageSize.TopRight.Y - topAux - topMargin - bottomMargin) - (pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin));
+
+ pageBuilder.SetTextAndFillColor(backColor.R, backColor.G, backColor.B);
+ pageBuilder.DrawRectangle(rectangleStartingPoint, width, height, 1, true);
+ }
+
+ pageBuilder.SetTextAndFillColor(foreColor.R, foreColor.G, foreColor.B);
+
+ if (fontUnderline)
+ {
+ float underlineSeparation = lineHeight / 5;
+ int underlineHeight = (int)underlineSeparation + (int)(underlineSeparation / 4);
+
+ PdfPoint underlineStartingPoint;
+ PdfPoint underlineEndingPoint;
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ underlineStartingPoint = new PdfPoint(
+ (leftAux + rightAux) / 2 + leftMargin - rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight
+ );
+ underlineEndingPoint = new PdfPoint(
+ (leftAux + rightAux) / 2 + leftMargin + rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight
+ );
+ break;
+ case 2: // Right Alignment
+ underlineStartingPoint = new PdfPoint(
+ rightAux + leftMargin - rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight
+ );
+ underlineEndingPoint = new PdfPoint(
+ rightAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight
+ );
+ break;
+ default: // Left Alignment (Corresponds to alignment = 0 but used as default)
+ underlineStartingPoint = new PdfPoint(
+ leftAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight
+ );
+ underlineEndingPoint = new PdfPoint(
+ leftAux + leftMargin + rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight
+ );
+ break;
+
+ }
+
+ pageBuilder.DrawLine(underlineStartingPoint, underlineEndingPoint, underlineHeight);
+ }
+
+ if (fontStrikethru)
+ {
+ float strikethruSeparation = (float)(lineHeight / 1.5);
+ PdfPoint strikethruStartingPoint;
+ PdfPoint strikethruEndingPoint;
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ strikethruStartingPoint = new PdfPoint(
+ (leftAux + rightAux) / 2 + leftMargin - rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight + strikethruSeparation
+ );
+ strikethruEndingPoint = new PdfPoint(
+ (leftAux + rightAux) / 2 + leftMargin + rectangleWidth / 2,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight + strikethruSeparation
+ );
+ break;
+ case 2: // Right Alignment
+ strikethruStartingPoint = new PdfPoint(
+ rightAux + leftMargin - rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight + strikethruSeparation
+ );
+ strikethruEndingPoint = new PdfPoint(
+ rightAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight + strikethruSeparation
+ );
+ break;
+ default: // Left Alignment (Corresponds to alignment = 0 but used as default)
+ strikethruStartingPoint = new PdfPoint(
+ leftAux + leftMargin,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight + strikethruSeparation
+ );
+ strikethruEndingPoint = new PdfPoint(
+ leftAux + leftMargin + rectangleWidth,
+ pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin + startHeight + strikethruSeparation
+ );
+ break;
+
+ }
+ pageBuilder.DrawLine(strikethruStartingPoint, strikethruEndingPoint, (decimal)convertScale(fontSize) / 10);
+ }
+
+ float textBlockWidth = rightAux - leftAux;
+ float TxtWidth = MeasureTextWidth(sTxt, baseFontPath, fontSize);
+ bool justified = (alignment == 3) && textBlockWidth < TxtWidth;
+ bool wrap = ((align & 16) == 16);
+
+ if (wrap || justified)
+ {
+ bottomAux = (float)convertScale(bottomOri);
+ topAux = (float)convertScale(topOri);
+
+ float llx = leftAux + leftMargin;
+ float lly = (float)(pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin);
+ float urx = rightAux + leftMargin;
+ float ury = (float)(pageBuilder.PageSize.TopRight.Y - topAux - topMargin - bottomMargin);
+
+ ShowWrappedTextAligned(font, alignment, sTxt, llx, lly, urx, ury);
+ }
+ else
+ {
+ if (!autoResize)
+ {
+ string newsTxt = sTxt;
+ while (TxtWidth > textBlockWidth && (newsTxt.Length - 1 >= 0))
+ {
+ sTxt = newsTxt;
+ newsTxt = newsTxt.Substring(0, newsTxt.Length - 1);
+ TxtWidth = MeasureTextWidth(sTxt, baseFontPath, fontSize);
+ }
+ }
+ switch (alignment)
+ {
+ case 1: // Center Alignment
+ ShowTextAligned(font, alignment, sTxt, ((leftAux + rightAux) / 2) + leftMargin, (float)(pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin));
+ break;
+ case 2: // Right Alignment
+ ShowTextAligned(font, alignment, sTxt, rightAux + leftMargin, (float)(pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin));
+ break;
+ case 0: // Left Alignment
+ case 3: // Justified, only one text line
+ ShowTextAligned(font, alignment, sTxt, leftAux + leftMargin, (float)(pageBuilder.PageSize.TopRight.Y - bottomAux - topMargin - bottomMargin));
+ break;
+ }
+ }
+ }
+
+ public Image CreateBarcodeImage(float width, float height, string fontPath, string text)
+ {
+ PrivateFontCollection fontCollection = new PrivateFontCollection();
+ fontCollection.AddFontFile(fontPath);
+ FontFamily fontFamily = fontCollection.Families[0];
+
+ int bitmapWidth = (int)Math.Ceiling(width);
+ int bitmapHeight = (int)Math.Ceiling(height);
+
+ float fontSize = Math.Min(width, height);
+ Font font;
+ SizeF textSize;
+
+ using (Bitmap tempBitmap = new Bitmap(1, 1))
+ {
+ using (Graphics tempGraphics = Graphics.FromImage(tempBitmap))
+ {
+ do
+ {
+ font = new Font(fontFamily, fontSize, GraphicsUnit.Pixel);
+ textSize = tempGraphics.MeasureString(text, font);
+ fontSize--;
+ } while (textSize.Width > width || textSize.Height > height);
+ }
+ }
+
+ Bitmap bitmap = new Bitmap(bitmapWidth, bitmapHeight);
+ bitmap.SetResolution(600, 600);
+ using (Graphics graphics = Graphics.FromImage(bitmap))
+ {
+ graphics.Clear(Color.White);
+ graphics.SmoothingMode = SmoothingMode.HighQuality;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
+ StringFormat format = new StringFormat
+ {
+ Alignment = StringAlignment.Center,
+ LineAlignment = StringAlignment.Center
+ };
+ graphics.DrawString(text, font, Brushes.Black, new RectangleF(0, 0, width, height), format);
+ }
+ font.Dispose();
+ fontCollection.Dispose();
+
+ return bitmap;
+ }
+
+ private float MeasureTextWidth(string text, string fontPath, float fontSize)
+ {
+ Font font;
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ font = new Font("Times New Roman", fontSize, GraphicsUnit.Point);
+ }
+ else
+ {
+ PrivateFontCollection pfc = new PrivateFontCollection();
+ pfc.AddFontFile(fontPath);
+ font = new Font(pfc.Families[0], fontSize, GraphicsUnit.Point);
+ }
+
+ using (font)
+ {
+ using (var fakeImage = new Bitmap(1, 1))
+ {
+ using (var graphics = Graphics.FromImage(fakeImage))
+ {
+ graphics.PageUnit = GraphicsUnit.Point;
+ graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
+ var sizeF = graphics.MeasureString(text, font);
+ return sizeF.Width;
+ }
+ }
+ }
+ }
+
+ private float MeasureTextHeight(string text, string fontPath, float fontSize)
+ {
+ Font font;
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ font = new Font("Times New Roman", fontSize, GraphicsUnit.Point);
+ }
+ else
+ {
+ PrivateFontCollection pfc = new PrivateFontCollection();
+ pfc.AddFontFile(fontPath);
+ font = new Font(pfc.Families[0], fontSize, GraphicsUnit.Point);
+ }
+
+ using (font)
+ {
+ using (var fakeImage = new Bitmap(1, 1))
+ {
+ using (var graphics = Graphics.FromImage(fakeImage))
+ {
+ graphics.PageUnit = GraphicsUnit.Point;
+ graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
+ var sizeF = graphics.MeasureString(text, font);
+ return sizeF.Height;
+ }
+ }
+ }
+ }
+
+ private float CalculateFontCaptionHeight(string fontPath, float fontSize, FontStyle fontStyle = FontStyle.Regular)
+ {
+ Font font;
+ if (string.IsNullOrEmpty(fontPath))
+ {
+ font = new Font("Times New Roman", fontSize, GraphicsUnit.Point);
+ }
+ else
+ {
+ PrivateFontCollection pfc = new PrivateFontCollection();
+ pfc.AddFontFile(fontPath);
+ font = new Font(pfc.Families[0], fontSize, GraphicsUnit.Point);
+ }
+ using (font)
+ {
+ FontFamily ff = font.FontFamily;
+
+ float ascent = ff.GetCellAscent(fontStyle);
+ float descent = ff.GetCellDescent(fontStyle);
+ float lineSpacing = ff.GetLineSpacing(fontStyle);
+
+ float height = fontSize * (ascent + descent) / ff.GetEmHeight(fontStyle);
+
+ return height;
+ }
+ }
+
+ private void ShowTextAligned(AddedFont font, int alignment, string text, float x, float y)
+ {
+ try
+ {
+ float textWidth = MeasureTextWidth(text, baseFontPath, fontSize);
+ switch (alignment)
+ {
+ case 0: // Left-aligned
+ case 3: // Justified, only one text line
+ break;
+ case 1: // Center-aligned
+ x = x - textWidth / 2;
+ break;
+ case 2: // Right-aligned
+ x = x - textWidth;
+ break;
+ }
+ y = (float)(y - fontSize * 0.5);
+ pageBuilder.AddText(text, fontSize, new PdfPoint(x, y), font);
+ }
+ catch (IOException ioe)
+ {
+ GXLogging.Error(log, "failed to draw aligned text: ", ioe);
+ }
+ }
+
+ private void ShowWrappedTextAligned(AddedFont font, int alignment, string text, float llx, float lly, float urx, float ury)
+ {
+ try
+ {
+ List lines = new List();
+ string[] words = text.Split(' ');
+ StringBuilder currentLine = new StringBuilder();
+ foreach (string word in words)
+ {
+ float currentLineWidth = MeasureTextWidth(currentLine + " " + word, baseFontPath, fontSize);
+ if (currentLineWidth < urx - llx)
+ {
+ if (currentLine.Length > 0)
+ {
+ currentLine.Append(" ");
+ }
+ currentLine.Append(word);
+ }
+ else
+ {
+ lines.Add(currentLine.ToString());
+ currentLine.Clear();
+ currentLine.Append(word);
+ }
+ }
+ lines.Add(currentLine.ToString());
+
+ float leading = (float)(lines.Count == 1 ? fontSize : 1.2 * fontSize);
+ float totalTextHeight = fontSize * lines.Count + leading * (lines.Count - 1);
+ float startY = lines.Count == 1 ? lly + (ury - lly - totalTextHeight) / 2 : lly + (ury - lly - totalTextHeight) / 2 + (lines.Count - 1) * (fontSize + leading);
+
+ foreach (string line in lines)
+ {
+ float lineWidth = MeasureTextWidth(line, baseFontPath, fontSize);
+ float startX;
+
+ switch (alignment)
+ {
+ case 1: // Center-aligned
+ startX = llx + (urx - llx - lineWidth) / 2;
+ break;
+ case 2: // Right-aligned
+ startX = urx - lineWidth;
+ break;
+ default: // Left-aligned & Justified, only one text line
+ startX = llx;
+ break;
+ }
+
+ pageBuilder.AddText(line, fontSize, new PdfPoint(startX, startY), font);
+ startY -= leading;
+ }
+ }
+ catch (IOException ioe)
+ {
+ GXLogging.Error(log, "Failed to draw wrapped text", ioe);
+ }
+ }
+
+ private ExtendedPageSize ComputePageSize(float leftMargin, float topMargin, int width, int length, bool marginsInsideBorder)
+ {
+ if ((leftMargin == 0 && topMargin == 0) || marginsInsideBorder)
+ {
+ if (length == 23818 && width == 16834)
+ return new ExtendedPageSize(PageSize.A3);
+ else if (length == 16834 && width == 11909)
+ return new ExtendedPageSize(PageSize.A4);
+ else if (length == 11909 && width == 8395)
+ return new ExtendedPageSize(PageSize.A5);
+ else if (length == 15120 && width == 10440)
+ return new ExtendedPageSize(PageSize.Executive);
+ else if (length == 20160 && width == 12240)
+ return new ExtendedPageSize(PageSize.Legal);
+ else if (length == 15840 && width == 12240)
+ return new ExtendedPageSize(PageSize.Letter);
+ else
+ return new ExtendedPageSize((width / PAGE_SCALE_X), (length / PAGE_SCALE_Y));
+ }
+ return new ExtendedPageSize((width / PAGE_SCALE_X) + leftMargin, (length / PAGE_SCALE_Y) + topMargin);
+
+ }
+
+ public override void GxEndDocument()
+ {
+ if (pages == 0)
+ {
+ GxStartPage();
+ }
+
+ GXLogging.Info(log, "The PDFPig API provides no way of setting the number of copies and the duplex value for the viewer preferences");
+
+ GXLogging.Info(log, "The PDFPig API provides no way of embedding javascript into the document");
+
+ try
+ {
+ byte[] documentBytes = documentBuilder.Build();
+ outputStream.Write(documentBytes, 0, documentBytes.Length);
+ }
+ catch (IOException e)
+ {
+ GXLogging.Debug(log,"GxEndDocument: failed to write document to the output stream", e);
+ }
+
+ string serverPrinting = props.getGeneralProperty(Const.SERVER_PRINTING);
+ bool printingScript = (outputType == Const.OUTPUT_PRINTER || outputType == Const.OUTPUT_STREAM_PRINTER) && serverPrinting.Equals("false");
+ switch (outputType)
+ {
+ case Const.OUTPUT_SCREEN:
+ try
+ {
+ outputStream.Close();
+ GXLogging.Debug(log, "GxEndDocument OUTPUT_SCREEN outputstream length" + outputStream.ToString().Length);
+ }
+ catch (IOException e)
+ {
+ GXLogging.Error(log, "GxEndDocument OUTPUT_SCREEN error", e);
+ }
+ try { showReport(docName, modal); }
+ catch (Exception) { }
+ break;
+
+ case Const.OUTPUT_PRINTER:
+ try { outputStream.Close(); }
+ catch (IOException) { }
+ try
+ {
+ if (!serverPrinting.Equals("false") && !printingScript)
+ {
+ printReport(docName, this.printerOutputMode == 0, printerSettings.getProperty(form, Const.PRINTER));
+ }
+ }
+ catch (Exception) { }
+ break;
+
+ case Const.OUTPUT_FILE:
+ try
+ {
+ outputStream.Close();
+ GXLogging.Debug(log, "GxEndDocument OUTPUT_FILE outputstream length" + outputStream.ToString().Length);
+ }
+ catch (IOException e)
+ {
+ GXLogging.Error(log, "GxEndDocument OUTPUT_FILE error", e);
+ }
+ break;
+
+ case Const.OUTPUT_STREAM:
+ case Const.OUTPUT_STREAM_PRINTER:
+ default: break;
+ }
+ outputStream = null;
+ }
+
+ }
+
+ internal class ExtendedPageSize
+ {
+ internal double Width;
+ internal double Height;
+ internal PageSize PageSize;
+ internal ExtendedPageSize(double w, double h)
+ {
+ Width = w;
+ Height = h;
+ PageSize = PageSize.Custom;
+ }
+ internal ExtendedPageSize(PageSize pageSize)
+ {
+ PageSize = pageSize;
+ }
+ internal bool IsCustomPageSize()
+ {
+ return PageSize == PageSize.Custom;
+ }
+ }
+}
diff --git a/dotnet/src/dotnetcore/GxPdfReportsCS/Properties/AssemblyInfo.cs b/dotnet/src/dotnetcore/GxPdfReportsCS/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..d916f63fa
--- /dev/null
+++ b/dotnet/src/dotnetcore/GxPdfReportsCS/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("DotNetCoreWebUnitTest")]
diff --git a/dotnet/src/dotnetcore/GxSearch/GxSearch.csproj b/dotnet/src/dotnetcore/GxSearch/GxSearch.csproj
index 826d61a8b..8588e6c64 100644
--- a/dotnet/src/dotnetcore/GxSearch/GxSearch.csproj
+++ b/dotnet/src/dotnetcore/GxSearch/GxSearch.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
1701;1702;NU1701;NU1603;CS0618
NETCORE
Lucene Search
@@ -20,22 +20,13 @@
-
+
-
+
-
-
-
- False
- ..\libs\Jayrock.dll
-
-
-
-
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/GxXsl/GxXsl.csproj b/dotnet/src/dotnetcore/GxXsl/GxXsl.csproj
index ece24ed17..d3f5fde98 100644
--- a/dotnet/src/dotnetcore/GxXsl/GxXsl.csproj
+++ b/dotnet/src/dotnetcore/GxXsl/GxXsl.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
GxXsl
GxXsl
XML xsl apply
diff --git a/dotnet/src/dotnetcore/Projects/StoreManager/StoreManager.csproj b/dotnet/src/dotnetcore/Projects/StoreManager/StoreManager.csproj
index fba3e8425..b4815e353 100644
--- a/dotnet/src/dotnetcore/Projects/StoreManager/StoreManager.csproj
+++ b/dotnet/src/dotnetcore/Projects/StoreManager/StoreManager.csproj
@@ -1,12 +1,14 @@
-
+
- net6.0
+ net6.0;net8.0
GeneXus.SD.Store.StoreManager
GeneXus.SD.Store
StoreManager
GeneXus.StoreManager.Core
-
+ NETCORE
+
+
@@ -25,8 +27,9 @@
-
+
+
@@ -36,10 +39,4 @@
-
-
- False
- ..\..\libs\Jayrock.dll
-
-
diff --git a/dotnet/src/dotnetcore/Providers/Cache/GxMemcached/GxMemcached.csproj b/dotnet/src/dotnetcore/Providers/Cache/GxMemcached/GxMemcached.csproj
index 46337bb8a..ecc9fba40 100644
--- a/dotnet/src/dotnetcore/Providers/Cache/GxMemcached/GxMemcached.csproj
+++ b/dotnet/src/dotnetcore/Providers/Cache/GxMemcached/GxMemcached.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
Memcached
GeneXus.Memcached.Core
NETCORE
@@ -15,8 +15,8 @@
-
-
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Cache/GxRedis/GxRedis.csproj b/dotnet/src/dotnetcore/Providers/Cache/GxRedis/GxRedis.csproj
index d83ab1b7f..f616027d3 100644
--- a/dotnet/src/dotnetcore/Providers/Cache/GxRedis/GxRedis.csproj
+++ b/dotnet/src/dotnetcore/Providers/Cache/GxRedis/GxRedis.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
Redis
GeneXus.Redis.Core
@@ -18,11 +18,14 @@
-
-
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSMessageQueueProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSMessageQueueProvider.cs
index ebf20e338..66b5394f0 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSMessageQueueProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSMessageQueueProvider.cs
@@ -21,8 +21,10 @@ public SimpleMessageQueue Connect(string queueURL, out GXBaseCollection errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
success = successConnect;
@@ -31,10 +33,12 @@ public SimpleMessageQueue Connect(string queueURL, out GXBaseCollection("Accesskey"));
- properties.Add("QUEUE_AWSSQS_SECRET_KEY", awsCredentials.GetPropertyValue("Secretkey"));
- properties.Add("QUEUE_AWSSQS_REGION", awsCredentials.GetPropertyValue("Region"));
+ GXProperties properties = new GXProperties
+ {
+ { "QUEUE_AWSSQS_ACCESS_KEY", awsCredentials.GetPropertyValue("Accesskey") },
+ { "QUEUE_AWSSQS_SECRET_KEY", awsCredentials.GetPropertyValue("Secretkey") },
+ { "QUEUE_AWSSQS_REGION", awsCredentials.GetPropertyValue("Region") }
+ };
return properties;
}
}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSQueue.cs
index f0ed5882d..47f31e184 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSQueue.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/AWSQueue.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using System.Reflection;
+using System.Threading.Tasks;
using Amazon;
using Amazon.Runtime;
using Amazon.SQS;
@@ -7,16 +9,13 @@
using GeneXus.Messaging.Common;
using GeneXus.Services;
using GeneXus.Utils;
-using log4net;
-using System.Threading.Tasks;
-using System.Reflection;
namespace GeneXus.Messaging.Queue
{
public class AWSQueue : QueueBase, IQueue
{
- public static String Name = "AWSSQS";
+ public static string Name = "AWSSQS";
const string ACCESS_KEY = "ACCESS_KEY";
const string SECRET_ACCESS_KEY = "SECRET_KEY";
const string REGION = "REGION";
@@ -31,7 +30,7 @@ public class AWSQueue : QueueBase, IQueue
public const string MESSSAGE_GROUP_ID = "MessageGroupId";
public const string MESSSAGE_DEDUPLICATION_ID = "MessageDeduplicationId";
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(AWSQueue));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
public AWSQueue() : this(null)
{
@@ -313,13 +312,14 @@ private MessageQueueResult SetupMessageQueueResult(SendMessageResponse response)
messageQueueResult.MessageId = response.MessageId;
messageQueueResult.MessageStatus = MessageQueueResultStatus.Sent;
- messageQueueResult.MessageAttributes = new GXProperties();
-
- messageQueueResult.MessageAttributes.Add("MD5OfMessageSystemAttributes", response.MD5OfMessageSystemAttributes);
- messageQueueResult.MessageAttributes.Add("MD5OfMessageAttributes", response.MD5OfMessageAttributes);
- messageQueueResult.MessageAttributes.Add("ContentLength", response.ContentLength.ToString());
- messageQueueResult.MessageAttributes.Add("MD5OfMessageBody", response.MD5OfMessageBody);
- messageQueueResult.MessageAttributes.Add("SequenceNumber", response.SequenceNumber);
+ messageQueueResult.MessageAttributes = new GXProperties
+ {
+ { "MD5OfMessageSystemAttributes", response.MD5OfMessageSystemAttributes },
+ { "MD5OfMessageAttributes", response.MD5OfMessageAttributes },
+ { "ContentLength", response.ContentLength.ToString() },
+ { "MD5OfMessageBody", response.MD5OfMessageBody },
+ { "SequenceNumber", response.SequenceNumber }
+ };
Type t = response.ResponseMetadata.GetType();
PropertyInfo[] props = t.GetProperties();
@@ -342,12 +342,13 @@ private MessageQueueResult SetupMessageQueueResult(SendMessageBatchResultEntry r
messageQueueResult.MessageId = response.Id;
messageQueueResult.MessageStatus = MessageQueueResultStatus.Sent;
- messageQueueResult.MessageAttributes = new GXProperties();
-
- messageQueueResult.MessageAttributes.Add("MD5OfMessageSystemAttributes", response.MD5OfMessageSystemAttributes);
- messageQueueResult.MessageAttributes.Add("MD5OfMessageAttributes", response.MD5OfMessageAttributes);
- messageQueueResult.MessageAttributes.Add("MD5OfMessageBody", response.MD5OfMessageBody);
- messageQueueResult.MessageAttributes.Add("SequenceNumber", response.SequenceNumber);
+ messageQueueResult.MessageAttributes = new GXProperties
+ {
+ { "MD5OfMessageSystemAttributes", response.MD5OfMessageSystemAttributes },
+ { "MD5OfMessageAttributes", response.MD5OfMessageAttributes },
+ { "MD5OfMessageBody", response.MD5OfMessageBody },
+ { "SequenceNumber", response.SequenceNumber }
+ };
return messageQueueResult;
}
@@ -378,11 +379,12 @@ private SimpleQueueMessage SetupSimpleQueueMessage(Message response)
simpleQueueMessage.MessageBody = response.Body;
simpleQueueMessage.MessageHandleId = response.ReceiptHandle;
- simpleQueueMessage.MessageAttributes = new GXProperties();
-
- simpleQueueMessage.MessageAttributes.Add("MD5OfMessageAttributes", response.MD5OfMessageAttributes);
- simpleQueueMessage.MessageAttributes.Add("MD5OfBody", response.MD5OfBody);
-
+ simpleQueueMessage.MessageAttributes = new GXProperties
+ {
+ { "MD5OfMessageAttributes", response.MD5OfMessageAttributes },
+ { "MD5OfBody", response.MD5OfBody }
+ };
+
foreach (var messageAttribute in response.MessageAttributes)
{
MessageAttributeValue messageAttributeValue = messageAttribute.Value;
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/GXAmazonSQS.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/GXAmazonSQS.csproj
index 53ad7604c..525f3c3c1 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/GXAmazonSQS.csproj
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAmazonSQS/GXAmazonSQS.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net6.0;net8.0
GeneXus.AWS.Queue
AWS SQS Queue Messaging
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/AzureEventGrid.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/AzureEventGrid.cs
new file mode 100644
index 000000000..821a7242a
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/AzureEventGrid.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Azure;
+using Azure.Identity;
+using Azure.Messaging;
+using Azure.Messaging.EventGrid;
+using GeneXus.Messaging.Common;
+using GeneXus.Services;
+using GeneXus.Utils;
+
+namespace GeneXus.Messaging.GXAzureEventGrid
+{
+ public class AzureEventGrid : EventRouterBase, IEventRouter
+ {
+ public static string Name = "AZUREEVENTGRID";
+ private EventGridPublisherClient _client;
+ private string _endpoint;
+ private string _accessKey;
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
+ public AzureEventGrid() : this(null)
+ {
+ }
+ public AzureEventGrid(GXService providerService) : base(providerService)
+ {
+ Initialize(providerService);
+ }
+ private void Initialize(GXService providerService)
+ {
+ ServiceSettings serviceSettings = new(PropertyConstants.EVENT_ROUTER, Name, providerService);
+ _endpoint = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.URI_ENDPOINT);
+ _accessKey = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.ACCESS_KEY);
+
+ if (!string.IsNullOrEmpty(_endpoint)) {
+
+ if (!string.IsNullOrEmpty(_accessKey))
+ _client = new EventGridPublisherClient(
+ new Uri(_endpoint),
+ new AzureKeyCredential(_accessKey));
+ else
+ //Try authenticating using AD
+ {
+ ChainedTokenCredential credential = new ChainedTokenCredential(new ManagedIdentityCredential(), new ManagedIdentityCredential(Environment.GetEnvironmentVariable("AZURE_CLIENT_ID")), new EnvironmentCredential(), new AzureCliCredential());
+ GXLogging.Debug(logger,"Authentication using Oauth 2.0.");
+ _client = new EventGridPublisherClient(
+ new Uri(_endpoint),
+ credential);
+ }
+ }
+ else
+ throw new Exception("Endpoint URI must be set.");
+ }
+ public override string GetName()
+ {
+ return Name;
+ }
+
+ public bool SendEvent(GXCloudEvent gxCloudEvent, bool binaryData)
+ {
+ CloudEvent evt = ToCloudEvent(gxCloudEvent, binaryData);
+ bool success = false;
+ Task task;
+ if (_client != null)
+ {
+ task = Task.Run(async () => await sendEvtAsync(evt).ConfigureAwait(false));
+ success = task.Result;
+ }
+ else
+ {
+ throw new Exception("There was an error at the Event Grid initialization.");
+ }
+ return success;
+ }
+ public bool SendEvents(IList gxCloudEvents, bool binaryData)
+ {
+ List evts = new List();
+ foreach (GXCloudEvent e in gxCloudEvents)
+ evts.Add(ToCloudEvent(e, binaryData));
+
+ bool success = false;
+ Task task;
+ if (_client != null)
+ {
+ task = Task.Run(async () => await sendEvtsAsync(evts).ConfigureAwait(false));
+ success = task.Result;
+ }
+ else
+ {
+ throw new Exception("There was an error at the Event Grid initialization.");
+ }
+ return success;
+ }
+ public bool SendCustomEvents(string jsonString, bool isBinary)
+ {
+ if (string.IsNullOrEmpty(jsonString))
+ {
+ throw new Exception("Events cannot be empty.");
+ }
+ try
+ {
+ List evts = JsonSerializer.Deserialize>(jsonString);
+
+ IList eventGridEvents = new List();
+ foreach (GXEventGridSchema e in evts)
+ eventGridEvents.Add(ToEventGridSchema(e,isBinary));
+
+ bool success = false;
+ try
+ {
+ Task task;
+ if (_client != null)
+ {
+ task = Task.Run(async () => await sendEventGridSchemaEventsAsync(eventGridEvents).ConfigureAwait(false));
+ success = task.Result;
+ }
+ else
+ {
+ throw new Exception("There was an error at the Event Grid initialization.");
+ }
+ }
+ catch (AggregateException ae)
+ {
+ throw ae;
+ }
+ return success;
+ }
+ catch (JsonException)
+ {
+ try
+ {
+ GXEventGridSchema evt = JsonSerializer.Deserialize(jsonString);
+ bool success = false;
+ try
+ {
+ Task task;
+ if (_client != null)
+ {
+ task = Task.Run(async () => await sendEventGridSchemaEventAsync(ToEventGridSchema(evt, isBinary)).ConfigureAwait(false));
+ success = task.Result;
+ }
+ else
+ {
+ throw new Exception("There was an error at the Event Grid initialization.");
+ }
+ }
+ catch (AggregateException ae)
+ {
+ throw ae;
+ }
+ return success;
+ }
+ catch (JsonException)
+ {
+ throw new Exception("jsonEvents parameter format is no correct. Valid format is AzureEventGrid.EventGridSchema SDT.");
+ }
+ }
+ }
+
+ #region Async methods
+ ///
+ /// Send asynchronously an event formatted as Azure EventGrid Schema.
+ ///
+ ///
+ /// bool
+ private async Task sendEventGridSchemaEventAsync(EventGridEvent evt)
+ {
+ Response response = await _client.SendEventAsync(evt).ConfigureAwait(false);
+ GXLogging.Debug(logger,string.Format("Send Event GridSchema: {0} {1}", response.Status, response.ReasonPhrase));
+ return !response.IsError;
+
+ }
+ ///
+ /// Send asynchronously a list of events formatted as Azure EventGrid Schema.
+ ///
+ ///
+ /// bool
+ private async Task sendEventGridSchemaEventsAsync(IEnumerable evts)
+ {
+ Response response = await _client.SendEventsAsync(evts).ConfigureAwait(false);
+ GXLogging.Debug(logger,string.Format("Send Events GridSchema: {0} {1}", response.Status, response.ReasonPhrase));
+ return !response.IsError;
+ }
+ ///
+ /// Send asynchronously an event formatted as CloudEvent Schema.
+ ///
+ ///
+ /// bool
+ private async Task sendEvtAsync(CloudEvent cloudEvent)
+ {
+ Response response = await _client.SendEventAsync(cloudEvent).ConfigureAwait(false);
+ GXLogging.Debug(logger,string.Format("Send Event: {0} {1}", response.Status,response.ReasonPhrase));
+ return !response.IsError;
+ }
+ ///
+ /// Send asynchronously a list of CloudEvent Schema formatted events.
+ ///
+ ///
+ /// bool
+ private async Task sendEvtsAsync(IEnumerable cloudEvents)
+ {
+ Response response = await _client.SendEventsAsync(cloudEvents).ConfigureAwait(false);
+ GXLogging.Debug(logger,string.Format("Send Events: {0} {1}", response.Status, response.ReasonPhrase));
+ return !response.IsError;
+ }
+
+ #endregion
+
+ #region TransformMethods
+ public bool GetMessageFromException(Exception ex, SdtMessages_Message msg)
+ {
+ try
+ {
+ RequestFailedException az_ex = (RequestFailedException)ex;
+ msg.gxTpr_Id = az_ex.ErrorCode.ToString();
+ msg.gxTpr_Description = az_ex.Message;
+ return true;
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ private EventGridEvent ToEventGridSchema(GXEventGridSchema gxEventGridSchema, bool isBinary)
+ {
+ EventGridEvent evt;
+ if (isBinary && !string.IsNullOrEmpty(gxEventGridSchema.data))
+ {
+ BinaryData binaryData = new BinaryData(gxEventGridSchema.data);
+ evt = new EventGridEvent(gxEventGridSchema.subject, gxEventGridSchema.eventtype, gxEventGridSchema.dataversion, binaryData);}
+ else
+ evt = new EventGridEvent(gxEventGridSchema.subject, gxEventGridSchema.eventtype, gxEventGridSchema.dataversion, gxEventGridSchema.data, null);
+ if (!string.IsNullOrEmpty(gxEventGridSchema.id))
+ evt.Id = gxEventGridSchema.id;
+ if (!string.IsNullOrEmpty(gxEventGridSchema.topic))
+ evt.Topic = gxEventGridSchema.topic;
+ if (gxEventGridSchema.eventtime != DateTime.MinValue)
+ evt.EventTime = gxEventGridSchema.eventtime;
+
+ return evt;
+ }
+ private CloudEvent ToCloudEvent(GXCloudEvent gxCloudEvent, bool isBinaryData)
+ {
+ CloudEvent evt;
+ Dictionary emptyData = new Dictionary();
+ if (string.IsNullOrEmpty(gxCloudEvent.data))
+ evt = new CloudEvent(source:gxCloudEvent.source, type:gxCloudEvent.type, emptyData);
+ else
+ {
+ if (!isBinaryData)
+ {
+ if (string.IsNullOrEmpty(gxCloudEvent.datacontenttype))
+ gxCloudEvent.datacontenttype = "application/json";
+ evt = new CloudEvent(gxCloudEvent.source, gxCloudEvent.type, BinaryData.FromString(gxCloudEvent.data),gxCloudEvent.datacontenttype,CloudEventDataFormat.Json);
+ }
+ else
+ {
+ if (string.IsNullOrEmpty(gxCloudEvent.datacontenttype))
+ gxCloudEvent.datacontenttype = "application/octet-stream";
+ evt = new CloudEvent(gxCloudEvent.source, gxCloudEvent.type, BinaryData.FromString(gxCloudEvent.data), gxCloudEvent.datacontenttype,CloudEventDataFormat.Binary);
+ }
+ }
+ if (!string.IsNullOrEmpty(gxCloudEvent.id))
+ evt.Id = gxCloudEvent.id;
+ if (!string.IsNullOrEmpty(gxCloudEvent.dataschema))
+ evt.DataSchema = gxCloudEvent.dataschema;
+ if (!string.IsNullOrEmpty(gxCloudEvent.subject))
+ evt.Subject = gxCloudEvent.subject;
+ if (gxCloudEvent.time != DateTime.MinValue)
+ evt.Time = gxCloudEvent.time;
+ return evt;
+ }
+ #endregion
+ }
+
+ [DataContract]
+ public class GXEventGridSchema
+ {
+ [DataMember]
+ public string topic { get; set; }
+ [DataMember]
+ public string eventtype { get; set; }
+ [DataMember]
+ public string id { get; set; }
+ [DataMember]
+ public string subject { get; set; }
+ [DataMember]
+ public string data { get; set; }
+ [DataMember]
+ public string dataversion { get; set; }
+
+ [DataMember]
+ public DateTime eventtime { get; set; }
+
+ [DataMember]
+ public string metadataversion { get; set; }
+
+
+ }
+}
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/EventGridRouterProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/EventGridRouterProvider.cs
new file mode 100644
index 000000000..f8c9e20ae
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/EventGridRouterProvider.cs
@@ -0,0 +1,26 @@
+using GeneXus.Messaging.Common;
+using GeneXus.Utils;
+
+namespace GeneXus.Messaging.GXAzureEventGrid
+{
+ ///
+ /// Implementation of EventGridRouterProvider External Object.
+ ///
+ public class EventGridRouterProvider
+ {
+ public EventRouterProviderBase Connect(string endpoint, string accesskey, out GXBaseCollection errorMessages, out bool success)
+ {
+ EventRouterProvider eventRouterProvider = new EventRouterProvider();
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.EVENTROUTER_AZUREEG_ENDPOINT, endpoint },
+ { PropertyConstants.EVENTROUTER_AZUREEG_ACCESS_KEY, accesskey }
+ };
+
+ EventRouterProviderBase evtRouterProvider = eventRouterProvider.Connect(PropertyConstants.AZUREEVENTGRID, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ errorMessages = errorMessagesConnect;
+ success = successConnect;
+ return evtRouterProvider;
+ }
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/GXAzureEventGrid.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/GXAzureEventGrid.csproj
new file mode 100644
index 000000000..5aebdae39
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/GXAzureEventGrid.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net6.0;net8.0
+ GeneXus.Azure.EventGrid
+ Azure EventGrid Messaging
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureMessageQueueProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureMessageQueueProvider.cs
index 698d7c0cc..93a9f49df 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureMessageQueueProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureMessageQueueProvider.cs
@@ -3,16 +3,35 @@
namespace GeneXus.Messaging.Queue
{
+ ///
+ /// Implementation of AzureQueue.MessageQueueProvider external object.
+ ///
+ ///
public class AzureMessageQueueProvider
{
- private const string AZUREQUEUE = "AZUREQUEUE";
- public SimpleMessageQueue Connect(string queueName, string queueURL, out GXBaseCollection errorMessages, out bool success)
+ public SimpleMessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success)
{
MessageQueueProvider messageQueueProvider = new MessageQueueProvider();
- GXProperties properties = new GXProperties();
- properties.Add("QUEUE_AZUREQUEUE_QUEUENAME", queueName);
- properties.Add("QUEUE_AZUREQUEUE_CONNECTIONSTRING", queueURL);
- SimpleMessageQueue simpleMessageQueue = messageQueueProvider.Connect(AZUREQUEUE, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.QUEUE_AZUREQUEUE_QUEUENAME, queueName },
+ { PropertyConstants.QUEUE_AZUREQUEUE_CONNECTIONSTRING, connectionString },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.Password.ToString()}
+ };
+ SimpleMessageQueue simpleMessageQueue = messageQueueProvider.Connect(PropertyConstants.AZURE_QUEUE_PROVIDERTYPENAME, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ errorMessages = errorMessagesConnect;
+ success = successConnect;
+ return simpleMessageQueue;
+ }
+ public SimpleMessageQueue Authenticate(string queueURI, out GXBaseCollection errorMessages, out bool success)
+ {
+ MessageQueueProvider messageQueueProvider = new MessageQueueProvider();
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.QUEUE_AZUREQUEUE_QUEUEURI, queueURI },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.ActiveDirectory.ToString()}
+ };
+ SimpleMessageQueue simpleMessageQueue = messageQueueProvider.Connect(PropertyConstants.AZURE_QUEUE_PROVIDERTYPENAME, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
success = successConnect;
return simpleMessageQueue;
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureQueue.cs
index 6953c8080..ac8fb4c69 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureQueue.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/AzureQueue.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using Azure.Identity;
using Azure.Storage.Queues;
using Azure.Storage.Queues.Models;
using GeneXus.Messaging.Common;
@@ -11,18 +12,17 @@ namespace GeneXus.Messaging.Queue
{
public class AzureQueue : QueueBase, IQueue
{
+ public static string Name = "AZUREQUEUE";
- public static String Name = "AZUREQUEUE";
- const string QUEUE_NAME = "QUEUENAME";
- const string QUEUE_CONNECTION_STRING = "CONNECTIONSTRING";
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
QueueClient _queueClient { get; set; }
private string _queueName { get; set; }
private string _connectionString { get; set; }
+ private string _queueURI { get; set; }
public AzureQueue() : this(null)
- {
- }
+ {}
public AzureQueue(GXService providerService) : base(providerService)
{
@@ -31,16 +31,28 @@ public AzureQueue(GXService providerService) : base(providerService)
private void Initialize(GXService providerService)
{
- ServiceSettings serviceSettings = new("QUEUE", Name, providerService);
- _queueName = serviceSettings.GetEncryptedPropertyValue(QUEUE_NAME);
- _connectionString = serviceSettings.GetEncryptedPropertyValue(QUEUE_CONNECTION_STRING);
+ ServiceSettings serviceSettings = new(PropertyConstants.QUEUE_SERVICE_NAME, Name, providerService);
+ _queueName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUENAME);
+ _connectionString = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.CONNECTIONSTRING);
+ _queueURI = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUEURI);
+ string authenticationMethod = serviceSettings.GetPropertiesValue(PropertyConstants.AUTHENTICATION_METHOD);
QueueClientOptions queueClientOptions = new QueueClientOptions()
{
MessageEncoding = QueueMessageEncoding.Base64
};
- _queueClient = new QueueClient(_connectionString, _queueName, queueClientOptions);
+ if (authenticationMethod.Equals(AuthenticationMethod.ActiveDirectory.ToString()))
+ {
+ ChainedTokenCredential credential = new ChainedTokenCredential(new ManagedIdentityCredential(), new ManagedIdentityCredential(Environment.GetEnvironmentVariable("AZURE_CLIENT_ID")), new EnvironmentCredential(), new AzureCliCredential());
+ _queueClient = new QueueClient(new Uri(_queueURI), credential,queueClientOptions);
+ GXLogging.Debug(logger, "Authenticate to Azure Storage Queue using Active Directory authentication.");
+ }
+ else
+ {
+ _queueClient = new QueueClient(_connectionString, _queueName, queueClientOptions);
+ GXLogging.Debug(logger, "Authenticate to Azure Storage Queue using Access Keys.");
+ }
}
QueueClient QueueClient
@@ -59,11 +71,6 @@ public AzureQueue(string connectionString, string queueName)
_connectionString = connectionString;
}
- //public AzureQueue(Uri uri, TokenCredential tokenCredential)
- //{
- //_queueClient = new QueueClient(uri, tokenCredential);
- //}
-
public bool GetMessageFromException(Exception ex, SdtMessages_Message msg)
{
try
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj
index a9fc132d3..7ae7307f7 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj
@@ -1,13 +1,16 @@
- net6.0
+ net6.0;net8.0
GeneXus.Azure.Queue
Azure Queue Messaging
-
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs
index e00d3c3c4..7981f96db 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs
@@ -4,6 +4,7 @@
using System.Reflection;
using System.Runtime.Serialization;
using System.Threading.Tasks;
+using Azure.Identity;
using Azure.Messaging.ServiceBus;
using GeneXus.Messaging.Common;
using GeneXus.Services;
@@ -15,12 +16,14 @@ public class AzureServiceBus : MessageBrokerBase, IMessageBroker
{
private const int MAX_MESSAGES_DEFAULT = 10;
private const short LOCK_DURATION = 5;
- public static String Name = "AZURESB";
+ public static string Name = "AZURESB";
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
private ConcurrentDictionary> m_messages = new ConcurrentDictionary>();
ServiceBusClient _serviceBusClient { get; set; }
private string _queueOrTopicName { get; set; }
private string _connectionString { get; set; }
+ private string _fullyqualifiedNamespace { get; set; }
private string _subscriptionName { get; set; }
private ServiceBusSender _sender { get; set; }
private ServiceBusReceiver _receiver { get; set; }
@@ -41,15 +44,17 @@ private void Initialize(GXService providerService)
_queueOrTopicName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_NAME);
_connectionString = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_CONNECTION_STRING);
_subscriptionName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.TOPIC_SUBSCRIPTION);
+ _fullyqualifiedNamespace = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.FULLYQUALIFIEDNAMESPACE);
+ string authenticationMethod = serviceSettings.GetPropertiesValue(PropertyConstants.AUTHENTICATION_METHOD);
- string sessionEnabled = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.SESSION_ENABLED);
+ string sessionEnabled = serviceSettings.GetPropertiesValue(PropertyConstants.SESSION_ENABLED);
if (!string.IsNullOrEmpty(sessionEnabled))
_sessionEnabled = Convert.ToBoolean(sessionEnabled);
else
_sessionEnabled = false;
- string senderIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.SENDER_IDENTIFIER);
+ string senderIdentifier = serviceSettings.GetPropertiesValue(PropertyConstants.SENDER_IDENTIFIER);
ServiceBusSenderOptions serviceBusSenderOptions = new ServiceBusSenderOptions();
if (!string.IsNullOrEmpty(senderIdentifier))
@@ -58,7 +63,18 @@ private void Initialize(GXService providerService)
//TO DO Consider connection options here
//https://docs.microsoft.com/en-us/javascript/api/@azure/service-bus/servicebusclientoptions?view=azure-node-latest#@azure-service-bus-servicebusclientoptions-websocketoptions
- _serviceBusClient = new ServiceBusClient(_connectionString);
+ if (authenticationMethod.Equals(AuthenticationMethod.ActiveDirectory.ToString()))
+ {
+ ChainedTokenCredential credential = new ChainedTokenCredential(new ManagedIdentityCredential(), new ManagedIdentityCredential(Environment.GetEnvironmentVariable("AZURE_CLIENT_ID")), new EnvironmentCredential(), new AzureCliCredential());
+ _serviceBusClient = new ServiceBusClient(_fullyqualifiedNamespace, credential);
+ GXLogging.Debug(logger, "Authenticate to Azure Service Bus using Active Directory authentication.");
+ }
+ else
+ {
+ _serviceBusClient = new ServiceBusClient(_connectionString);
+ GXLogging.Debug(logger, "Authenticate to Azure Service Bus using SAS authentication.");
+ }
+
if (_serviceBusClient != null)
{
_sender = _serviceBusClient.CreateSender(_queueOrTopicName, serviceBusSenderOptions);
@@ -66,9 +82,9 @@ private void Initialize(GXService providerService)
{
_serviceBusReceiverOptions = new ServiceBusReceiverOptions();
- string receiveMode = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVE_MODE);
- string prefetchCount = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.PREFETCH_COUNT);
- string receiverIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_IDENTIFIER);
+ string receiveMode = serviceSettings.GetPropertiesValue(PropertyConstants.RECEIVE_MODE);
+ string prefetchCount = serviceSettings.GetPropertiesValue(PropertyConstants.PREFETCH_COUNT);
+ string receiverIdentifier = serviceSettings.GetPropertiesValue(PropertyConstants.RECEIVER_IDENTIFIER);
if (!string.IsNullOrEmpty(receiveMode))
_serviceBusReceiverOptions.ReceiveMode = (ServiceBusReceiveMode)Convert.ToInt16(receiveMode);
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj
index ac8137a4a..049e25bef 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj
@@ -1,13 +1,16 @@
- net6.0
+ net6.0;net8.0
GeneXus.Azure.ServiceBus
Azure ServiceBus Messaging
-
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs
index 036c89652..e1f0ab226 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs
@@ -5,14 +5,31 @@
namespace GeneXus.Messaging.GXAzureServiceBus
{
+ ///
+ /// Implementation of AzureServiceBus.MessageBrokerProvider external object.
+ ///
public class ServiceBusMessageBrokerProvider
{
- public MessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success)
+
+ #region Azure Active Directory Authentication
+
+ public MessageQueue Authenticate(string queueName, string fullyQualifiedNamespace, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success)
{
MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
- GXProperties properties = new GXProperties();
- properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName);
- properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString);
+ ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions);
+
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE, fullyQualifiedNamespace },
+ { PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString() },
+ { PropertyConstants.RECEIVE_MODE, options.ReceiveMode.ToString() },
+ { PropertyConstants.PREFETCH_COUNT, options.PrefetchCount.ToString() },
+ { PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier },
+ { PropertyConstants.RECEIVER_SESSIONID, options.SessionId },
+ { PropertyConstants.SENDER_IDENTIFIER, senderIdentifier },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.ActiveDirectory.ToString()}
+ };
MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
@@ -20,13 +37,90 @@ public MessageQueue Connect(string queueName, string connectionString, out GXBas
return messageQueue;
}
- public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, out GXBaseCollection errorMessages, out bool success)
+ public MessageQueue Authenticate(string topicName, string subcriptionName, string fullyQualifiedNamespace, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success)
{
MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
GXProperties properties = new GXProperties();
+ ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions);
+
properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, topicName);
properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName);
- properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString);
+ properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE, fullyQualifiedNamespace);
+ properties.Add(PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString());
+ properties.Add(PropertyConstants.RECEIVE_MODE, options.ReceiveMode.ToString());
+ properties.Add(PropertyConstants.PREFETCH_COUNT, options.PrefetchCount.ToString());
+ properties.Add(PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier);
+ properties.Add(PropertyConstants.RECEIVER_SESSIONID, options.SessionId);
+ properties.Add(PropertyConstants.SENDER_IDENTIFIER, senderIdentifier);
+ properties.Add(PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.ActiveDirectory.ToString());
+
+ MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ errorMessages = errorMessagesConnect;
+ success = successConnect;
+ return messageQueue;
+ }
+
+ public MessageQueue Authenticate(string queueName, string fullyQualifiedNamespace, out GXBaseCollection errorMessages, out bool success)
+ {
+ MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE, fullyQualifiedNamespace },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.ActiveDirectory.ToString()}
+ };
+
+ MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ errorMessages = errorMessagesConnect;
+ success = successConnect;
+ return messageQueue;
+ }
+ public MessageQueue Authenticate(string topicName, string subcriptionName, string fullyQualifiedNamespace, out GXBaseCollection errorMessages, out bool success)
+ {
+ MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, topicName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE, fullyQualifiedNamespace },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.ActiveDirectory.ToString()}
+ };
+
+ MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ errorMessages = errorMessagesConnect;
+ success = successConnect;
+ return messageQueue;
+ }
+ #endregion
+
+ #region Connect using SAS (Shared Access Signatures)
+ public MessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success)
+ {
+ MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.Password.ToString()}
+
+ };
+
+ MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
+ errorMessages = errorMessagesConnect;
+ success = successConnect;
+ return messageQueue;
+ }
+
+ public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, out GXBaseCollection errorMessages, out bool success)
+ {
+ MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, topicName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.Password.ToString()}
+ };
MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
@@ -39,15 +133,18 @@ public MessageQueue Connect(string queueName, string connectionString, bool sess
MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider();
ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions);
- GXProperties properties = new GXProperties();
- properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName);
- properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString);
- properties.Add(PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString());
- properties.Add(PropertyConstants.RECEIVE_MODE, options.ReceiveMode.ToString());
- properties.Add(PropertyConstants.PREFETCH_COUNT, options.PrefetchCount.ToString());
- properties.Add(PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier);
- properties.Add(PropertyConstants.RECEIVER_SESSIONID, options.SessionId);
- properties.Add(PropertyConstants.SENDER_IDENTIFIER, senderIdentifier);
+ GXProperties properties = new GXProperties
+ {
+ { PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName },
+ { PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString },
+ { PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString() },
+ { PropertyConstants.RECEIVE_MODE, options.ReceiveMode.ToString() },
+ { PropertyConstants.PREFETCH_COUNT, options.PrefetchCount.ToString() },
+ { PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier },
+ { PropertyConstants.RECEIVER_SESSIONID, options.SessionId },
+ { PropertyConstants.SENDER_IDENTIFIER, senderIdentifier },
+ { PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.Password.ToString()}
+ };
MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
@@ -70,6 +167,7 @@ public MessageQueue Connect(string topicName, string subcriptionName, string con
properties.Add(PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier);
properties.Add(PropertyConstants.RECEIVER_SESSIONID, options.SessionId);
properties.Add(PropertyConstants.SENDER_IDENTIFIER, senderIdentifier);
+ properties.Add(PropertyConstants.AUTHENTICATION_METHOD, AuthenticationMethod.Password.ToString());
MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
@@ -77,6 +175,8 @@ public MessageQueue Connect(string topicName, string subcriptionName, string con
return messageQueue;
}
+ #endregion
+
#region Transformation methods
private ReceiverOptions TransformGXUserTypeToReceiverOptions(GxUserType options)
{
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouter.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouter.cs
new file mode 100644
index 000000000..56fa53a2a
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using GeneXus.Utils;
+
+namespace GeneXus.Messaging.Common
+{
+ public interface IEventRouter
+ {
+ bool SendEvent(GXCloudEvent gxCloudEvent, bool binaryData);
+ bool SendEvents(IList gxCloudEvents, bool binaryData);
+ bool SendCustomEvents(string jsonString, bool isBinary);
+ bool GetMessageFromException(Exception ex, SdtMessages_Message msg);
+ }
+ public class GXCloudEvent : GxUserType
+ {
+ public string type { get; set; }
+ public string source { get; set; }
+ public string data { get; set; }
+ public string datacontenttype { get; set; }
+ public string id { get; set; }
+ public string dataschema { get; set; }
+ public string subject { get; set; }
+ public string data_base64 { get; set; }
+ public DateTime time { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterBase.cs
new file mode 100644
index 000000000..fb4d42cf5
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterBase.cs
@@ -0,0 +1,32 @@
+using System;
+using GeneXus.Services;
+
+namespace GeneXus.Messaging.Common
+{
+ public abstract class EventRouterBase
+ {
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
+ internal GXService service;
+ public EventRouterBase()
+ {
+ }
+
+ public EventRouterBase(GXService s)
+ {
+ if (s == null)
+ {
+ try
+ {
+ s = ServiceFactory.GetGXServices()?.Get(GXServices.EVENTROUTER_SERVICE);
+ }
+ catch (Exception)
+ {
+ GXLogging.Warn(logger, "EVENTROUTER_SERVICE is not activated");
+ }
+ }
+
+ service = s;
+ }
+ public abstract string GetName();
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProvider.cs
new file mode 100644
index 000000000..a9cf3b0e7
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProvider.cs
@@ -0,0 +1,112 @@
+using System;
+using GeneXus.Attributes;
+using GeneXus.Encryption;
+using GeneXus.Services;
+using GeneXus.Utils;
+using GxClasses.Helpers;
+
+namespace GeneXus.Messaging.Common
+{
+ [GXApi]
+ public class EventRouterProvider : EventRouterProviderBase
+ {
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
+ private static GXService providerService;
+ public EventRouterProvider() {
+ }
+ public EventRouterProviderBase Connect(string providerTypeName, GXProperties properties, out GXBaseCollection errorMessages, out bool success)
+ {
+ errorMessages = new GXBaseCollection();
+ EventRouterProviderBase eventRouter = new EventRouterProviderBase();
+ if (string.IsNullOrEmpty(providerTypeName))
+ {
+ GXUtil.ErrorToMessages("GXEventRouter", "Event Router provider cannot be empty", errorMessages);
+ GXLogging.Error(logger, "(GXEventRouter)Failed to Connect to a Event Router : Provider cannot be empty.");
+ success = false;
+ return eventRouter;
+ }
+ try
+ {
+ if (providerService == null || !string.Equals(providerService.Name, providerTypeName, StringComparison.OrdinalIgnoreCase))
+ {
+ providerService = new GXService();
+ providerService.Type = GXServices.EVENTROUTER_SERVICE;
+ providerService.Name = providerTypeName;
+ providerService.AllowMultiple = false;
+ providerService.Properties = new GXProperties();
+ }
+ Preprocess(providerTypeName, properties);
+
+ GxKeyValuePair prop = properties.GetFirst();
+ while (!properties.Eof())
+ {
+ providerService.Properties.Set(prop.Key, prop.Value);
+ prop = properties.GetNext();
+ }
+
+ string typeFullName = providerService.ClassName;
+ GXLogging.Debug(logger, "Loading Event Router provider: " + typeFullName);
+ Type type = AssemblyLoader.GetType(typeFullName);
+ eventRouter.eventRouter = (IEventRouter)Activator.CreateInstance(type, new object[] { providerService });
+
+ }
+ catch (Exception ex)
+ {
+ GXLogging.Error(logger, "(GXEventRouter)Couldn't connect to Event Router provider: " + ExceptionExtensions.GetInnermostException(ex));
+ GXUtil.ErrorToMessages("GXEventRouter", ex, errorMessages);
+ success = false;
+ return eventRouter;
+ }
+ success = true;
+ return (eventRouter);
+ }
+ private static void Preprocess(string name, GXProperties properties)
+ {
+ string className;
+
+ switch (name)
+ {
+ case Providers.AzureEventGrid:
+ className = PropertyConstants.AZURE_EG_CLASSNAME;
+ SetEncryptedProperty(properties, PropertyConstants.EVENTROUTER_AZUREEG_ENDPOINT);
+ SetEncryptedProperty(properties, PropertyConstants.EVENTROUTER_AZUREEG_ACCESS_KEY);
+ if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className))
+ {
+ providerService.ClassName = PropertyConstants.AZURE_EG_PROVIDER_CLASSNAME;
+ }
+ break;
+ default:
+ throw new SystemException(string.Format("Provider {0} is not supported.", name));
+ }
+ }
+ private static void SetEncryptedProperty(GXProperties properties, string prop)
+ {
+ string value = properties.Get(prop);
+ if (string.IsNullOrEmpty(value))
+ value = string.Empty;
+ value = CryptoImpl.Encrypt(value);
+ properties.Set(prop, value);
+ }
+
+ }
+ public static class ExceptionExtensions
+ {
+ public static string GetInnermostException(Exception e)
+ {
+ Exception ex = e;
+ if (ex != null)
+ {
+ while (ex.InnerException != null)
+ {
+ ex = ex.InnerException;
+ }
+
+ }
+ return ex.Message;
+ }
+ }
+ static class Providers
+ {
+ public const string AzureEventGrid = "AZUREEVENTGRID";
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProviderBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProviderBase.cs
new file mode 100644
index 000000000..25acbc4cf
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProviderBase.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using GeneXus.Services;
+using GeneXus.Utils;
+using GxClasses.Helpers;
+
+namespace GeneXus.Messaging.Common
+{
+ public class EventRouterProviderBase
+ {
+ internal IEventRouter eventRouter = null;
+ public static Assembly assembly;
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
+ private const string MODULE_DLL = @"GeneXusEventMessaging";
+
+ public EventRouterProviderBase()
+ {
+ }
+ public EventRouterProviderBase(EventRouterProviderBase other)
+ {
+ eventRouter = other.eventRouter;
+ }
+ void ValidQueue()
+ {
+ if (eventRouter == null)
+ {
+ GXLogging.Error(logger, "Event Router was not instantiated.");
+ throw new Exception("Event Router was not instantiated.");
+ }
+ }
+ private static void LoadAssemblyIfRequired()
+ {
+ if (assembly == null)
+ {
+ assembly = AssemblyLoader.LoadAssembly(new AssemblyName(MODULE_DLL));
+ }
+ }
+
+ public bool SendEvent(GxUserType evt, bool binaryData, out GXBaseCollection errorMessages)
+ {
+ bool success = false;
+ errorMessages = new GXBaseCollection();
+ try
+ {
+ GXCloudEvent gxCloudEvent = ToGXCloudEvent(evt);
+ LoadAssemblyIfRequired();
+ try
+ {
+ ValidQueue();
+ if (eventRouter != null)
+ return(eventRouter.SendEvent(gxCloudEvent, binaryData));
+ }
+ catch (Exception ex)
+ {
+ EventRouterErrorMessagesSetup(ex, out errorMessages);
+ success = false;
+ GXLogging.Error(logger, ex);
+ }
+ }
+ catch (Exception ex)
+ {
+ success = false;
+ GXLogging.Error(logger,ex);
+ throw ex;
+ }
+ return success;
+ }
+
+ public bool SendCustomEvents(string evts, bool isBinary, out GXBaseCollection errorMessages)
+ {
+ errorMessages = new GXBaseCollection();
+ bool success;
+ try
+ {
+ ValidQueue();
+ success = eventRouter.SendCustomEvents(evts, isBinary);
+ }
+ catch (Exception ex)
+ {
+ EventRouterErrorMessagesSetup(ex, out errorMessages);
+ success = false;
+ GXLogging.Error(logger, ex);
+ }
+ return success;
+ }
+
+ public bool SendEvents(IList evts, bool binaryData, out GXBaseCollection errorMessages)
+ {
+ errorMessages = new GXBaseCollection();
+ bool success = false;
+ LoadAssemblyIfRequired();
+ try
+ {
+ IList gxCloudEvents = new List();
+ foreach (GxUserType e in evts)
+ {
+ if (ToGXCloudEvent(e) is GXCloudEvent gxCloudEvent)
+ gxCloudEvents.Add(gxCloudEvent);
+ }
+ try
+ {
+ ValidQueue();
+ success = eventRouter.SendEvents(gxCloudEvents, binaryData);
+ }
+ catch (Exception ex)
+ {
+ EventRouterErrorMessagesSetup(ex, out errorMessages);
+ success = false;
+ GXLogging.Error(logger, ex);
+ }
+ }
+ catch (Exception ex)
+ {
+ GXLogging.Error(logger, ex);
+ throw ex;
+ }
+ return success;
+ }
+
+ #region Transform operations
+ protected void EventRouterErrorMessagesSetup(Exception ex, out GXBaseCollection errorMessages)
+ {
+ errorMessages = new GXBaseCollection();
+ bool foundGeneralException = false;
+ if (ex != null)
+ {
+ SdtMessages_Message msg = new SdtMessages_Message();
+ if (eventRouter != null && ex.InnerException != null)
+ {
+ do
+ {
+ if (eventRouter.GetMessageFromException(ex.InnerException, msg))
+ {
+ msg.gxTpr_Type = 1;
+ errorMessages.Add(msg);
+ }
+ else
+ {
+ foundGeneralException = true;
+ break;
+ }
+ ex = ex.InnerException;
+ }
+ while (ex.InnerException != null);
+ if (foundGeneralException)
+ GXUtil.ErrorToMessages("GXEventRouter", ex, errorMessages);
+ }
+ else
+ {
+ GXUtil.ErrorToMessages("GXEventRouter", ex, errorMessages);
+ }
+ }
+ }
+ private GXCloudEvent ToGXCloudEvent(GxUserType evt)
+ {
+ if (evt != null)
+ {
+ GXCloudEvent gxCloudEvent = new GXCloudEvent();
+ gxCloudEvent.type = evt.GetPropertyValue("Type");
+ gxCloudEvent.source = evt.GetPropertyValue("Source");
+ gxCloudEvent.data = evt.GetPropertyValue("Data");
+ gxCloudEvent.datacontenttype = evt.GetPropertyValue("Datacontenttype");
+ gxCloudEvent.id = evt.GetPropertyValue("Id");
+ gxCloudEvent.subject = evt.GetPropertyValue("Subject");
+ gxCloudEvent.dataschema = evt.GetPropertyValue("Dataschema");
+ gxCloudEvent.data_base64 = evt.GetPropertyValue("Data_base64");
+ gxCloudEvent.time = evt.GetPropertyValue("Time");
+ return gxCloudEvent;
+ }
+ return null;
+ }
+ #endregion
+
+ }
+ internal class ServiceFactory
+ {
+ private static IEventRouter eventRouter;
+ static readonly IGXLogger log = GXLoggerFactory.GetLogger();
+
+ public static GXServices GetGXServices()
+ {
+ return GXServices.Instance;
+ }
+
+ public static IEventRouter GetEventRouter()
+ {
+ if (eventRouter == null)
+ {
+ eventRouter = GetRouterImpl(GXServices.EVENTROUTER_SERVICE);
+ }
+ return eventRouter;
+ }
+
+ public static IEventRouter GetRouterImpl(string service)
+ {
+ IEventRouter eventRouterImpl = null;
+ if (GetGXServices() != null)
+ {
+ GXService providerService = GetGXServices()?.Get(service);
+ if (providerService != null)
+ {
+ try
+ {
+ string typeFullName = providerService.ClassName;
+ GXLogging.Debug(log, "Loading Event Router settings:", typeFullName);
+ Type type = AssemblyLoader.GetType(typeFullName);
+ eventRouterImpl = (IEventRouter)Activator.CreateInstance(type);
+ }
+ catch (Exception e)
+ {
+ GXLogging.Error(log, "Couldn't connect to the Event Router.", e.Message, e);
+ throw e;
+ }
+ }
+ }
+ return eventRouterImpl;
+ }
+ }
+}
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/GXEventRouter.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/GXEventRouter.csproj
new file mode 100644
index 000000000..cdf1f3ab0
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/GXEventRouter.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net6.0;net8.0
+ GeneXus.Message.EventRouter
+ Event Bus Messaging Router
+ TRACE;DEBUG;NETCORE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/PropertyConstants.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/PropertyConstants.cs
new file mode 100644
index 000000000..2aed7d804
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/PropertyConstants.cs
@@ -0,0 +1,17 @@
+namespace GeneXus.Messaging.Common
+{
+ public static class PropertyConstants
+ {
+ //Azure Event Grid
+
+ internal const string AZURE_EG_CLASSNAME = "GeneXus.Messaging.GXAzureEventGrid.AzureEventGrid";
+ internal const string AZURE_EG_PROVIDER_CLASSNAME = "GeneXus.Messaging.GXAzureEventGrid.AzureEventGrid, GXAzureEventGrid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
+ public const string EVENT_ROUTER = "EVENTROUTER";
+ public const string URI_ENDPOINT = "ENDPOINT";
+ public const string ACCESS_KEY = "ACCESS_KEY";
+ public const string AZUREEVENTGRID = "AZUREEVENTGRID";
+ public const string EVENTROUTER_AZUREEG_ENDPOINT = "EVENTROUTER_AZUREEVENTGRID_ENDPOINT";
+ public const string EVENTROUTER_AZUREEG_ACCESS_KEY = "EVENTROUTER_AZUREEVENTGRID_ACCESS_KEY";
+
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj
index a1fc0121d..d40bc0234 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj
@@ -1,12 +1,17 @@
- net6.0
+ net6.0;net8.0
GeneXus.Message.MessageBroker
Broker Messaging
TRACE;DEBUG;NETCORE
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs
index 031837384..de6c1bece 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs
@@ -1,12 +1,11 @@
using System;
using GeneXus.Services;
-using log4net;
namespace GeneXus.Messaging.Common
{
public abstract class MessageBrokerBase
{
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(MessageBrokerBase));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
internal GXService service;
public MessageBrokerBase()
{
@@ -28,6 +27,6 @@ public MessageBrokerBase(GXService s)
service = s;
}
- public abstract String GetName();
+ public abstract string GetName();
}
}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs
index c3acfb7d8..69179faa5 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs
@@ -4,14 +4,13 @@
using GeneXus.Services;
using GeneXus.Utils;
using GxClasses.Helpers;
-using log4net;
namespace GeneXus.Messaging.Common
{
[GXApi]
public class MessageBrokerProvider : MessageQueue
{
- static readonly ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
private static GXService providerService;
public MessageBrokerProvider()
{
@@ -64,7 +63,7 @@ public MessageQueue Connect(string providerTypeName, GXProperties properties, ou
success = true;
return (messageQueue);
}
- private static void Preprocess(String name, GXProperties properties)
+ private static void Preprocess(string name, GXProperties properties)
{
string className;
@@ -75,6 +74,7 @@ private static void Preprocess(String name, GXProperties properties)
SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME);
SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME);
SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING);
+ SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE);
if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className))
{
providerService.ClassName = PropertyConstants.AZURE_SB_PROVIDER_CLASSNAME;
@@ -84,11 +84,11 @@ private static void Preprocess(String name, GXProperties properties)
throw new SystemException(string.Format("Provider {0} is not supported.", name));
}
}
- private static void SetEncryptedProperty(GXProperties properties, String prop)
+ private static void SetEncryptedProperty(GXProperties properties, string prop)
{
- String value = properties.Get(prop);
+ string value = properties.Get(prop);
if (string.IsNullOrEmpty(value))
- value = String.Empty;
+ value = string.Empty;
value = CryptoImpl.Encrypt(value);
properties.Set(prop, value);
}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs
index 344626aa0..13f6c7702 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs
@@ -3,11 +3,9 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
-using System.Text;
using GeneXus.Services;
using GeneXus.Utils;
using GxClasses.Helpers;
-using log4net;
namespace GeneXus.Messaging.Common
{
@@ -15,7 +13,7 @@ public class MessageQueue
{
internal IMessageBroker messageBroker = null;
public static Assembly assembly;
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(MessageQueue));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
private const string SDT_MESSAGE_CLASS_NAME = @"SdtMessage";
private const string SDT_MESSAGEPROPERTY_CLASS_NAME = @"SdtMessageProperty";
private const string NAMESPACE = @"GeneXus.Programs.genexusmessagingmessagebroker";
@@ -257,12 +255,12 @@ protected void QueueErrorMessagesSetup(Exception ex, out GXBaseCollection();
bool foundGeneralException = false;
- if (errorMessages != null && ex != null)
+ if (ex != null)
{
SdtMessages_Message msg = new SdtMessages_Message();
- if (messageBroker != null)
- {
- while (ex.InnerException != null)
+ if (messageBroker != null && ex.InnerException != null)
+ {
+ do
{
if (messageBroker.GetMessageFromException(ex.InnerException, msg))
{
@@ -276,6 +274,7 @@ protected void QueueErrorMessagesSetup(Exception ex, out GXBaseCollection();
public static GXServices GetGXServices()
{
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs
index 9c5ed2930..7a8d6c09e 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs
@@ -16,10 +16,19 @@ public static class PropertyConstants
public const string MESSAGEBROKER_AZURESB_TOPICNAME = "MESSAGEBROKER_AZURESB_TOPICNAME";
public const string MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME = "MESSAGEBROKER_AZURESB_SUBSCRIPTION";
public const string MESSAGEBROKER_AZURESB_CONNECTIONSTRING = "MESSAGEBROKER_AZURESB_QUEUECONNECTION";
+ public const string MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE = "MESSAGEBROKER_AZURESB_FULLYQUALIFIEDNAMESPACE";
public const string QUEUE_NAME = "QUEUENAME";
public const string QUEUE_CONNECTION_STRING = "QUEUECONNECTION";
+ public const string FULLYQUALIFIEDNAMESPACE = "FULLYQUALIFIEDNAMESPACE";
public const string TOPIC_SUBSCRIPTION = "SUBSCRIPTION";
public const string MESSAGE_BROKER = "MESSAGEBROKER";
public const string SESSION_ENABLED = "SESSION_ENABLED";
+
+ public const string AUTHENTICATION_METHOD = "AUTHENTICATION_METHOD";
}
+ public enum AuthenticationMethod
+ {
+ ActiveDirectory,
+ Password
+ }
}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs
index 2d920710c..f718b6c4e 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs
@@ -1,18 +1,12 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using GeneXus.Encryption;
-using GeneXus.Messaging.Common;
using GeneXus.Services;
-using log4net;
namespace GeneXus.Messaging.Common
{
public class ServiceSettings
{
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(ServiceSettings));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
internal GXService service;
public string serviceNameResolver { get; }
@@ -22,33 +16,32 @@ public ServiceSettings(string serviceNameResolver, string name, GXService gXServ
{
this.serviceNameResolver = serviceNameResolver;
this.name = name;
- this.service = gXService;
+ service = gXService;
}
- public string GetEncryptedOptPropertyValue(string propertyName, string alternativePropertyName = null)
+ public string GetPropertiesValue(string propertyName)
{
- String value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null);
- return value;
+ return service.Properties.Get(propertyName);
}
public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName = null)
{
- String value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null);
+ string value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null);
if (value == null)
{
- String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
- logger.Fatal(errorMessage);
+ string errorMessage = string.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
+ GXLogging.Error(logger, errorMessage);
throw new Exception(errorMessage);
}
return value;
}
public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName, string defaultValue)
{
- String value = GetPropertyValue(propertyName, alternativePropertyName, defaultValue);
- if (!String.IsNullOrEmpty(value))
+ string value = GetPropertyValue(propertyName, alternativePropertyName, defaultValue);
+ if (!string.IsNullOrEmpty(value))
{
try
{
- string ret = String.Empty;
+ string ret = string.Empty;
if (CryptoImpl.Decrypt(ref ret, value))
{
value = ret;
@@ -56,7 +49,7 @@ public string GetEncryptedPropertyValue(string propertyName, string alternativeP
}
catch (Exception)
{
- logger.Warn($"Could not decrypt property name: {ResolvePropertyName(propertyName)}");
+ GXLogging.Warn(logger, $"Could not decrypt property name: {ResolvePropertyName(propertyName)}");
}
}
return value;
@@ -64,11 +57,11 @@ public string GetEncryptedPropertyValue(string propertyName, string alternativeP
internal string GetPropertyValue(string propertyName, string alternativePropertyName = null)
{
- String value = GetPropertyValue(propertyName, alternativePropertyName, null);
+ string value = GetPropertyValue(propertyName, alternativePropertyName, null);
if (value == null)
{
- String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
- logger.Fatal(errorMessage);
+ string errorMessage = string.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
+ GXLogging.Error(logger,errorMessage);
throw new Exception(errorMessage);
}
return value;
@@ -76,7 +69,7 @@ internal string GetPropertyValue(string propertyName, string alternativeProperty
internal string GetPropertyValue(string propertyName, string alternativePropertyName, string defaultValue)
{
- String value = null;
+ string value = null;
value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(ResolvePropertyName(propertyName)) : value;
value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(propertyName) : value;
value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(alternativePropertyName) : value;
@@ -86,7 +79,7 @@ internal string GetPropertyValue(string propertyName, string alternativeProperty
internal string GetPropertyValueImpl(string propertyName)
{
- String value = null;
+ string value = null;
if (!string.IsNullOrEmpty(propertyName))
{
value = Environment.GetEnvironmentVariable(propertyName);
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj
index b41e066ac..bce3bd249 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj
@@ -1,10 +1,18 @@
- net6.0
+ net6.0;net8.0
TRACE;DEBUG;NETCORE
GeneXus.Message.Queue
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/MessageQueueProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/MessageQueueProvider.cs
index 90d951738..cf6077c65 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/MessageQueueProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/MessageQueueProvider.cs
@@ -4,18 +4,15 @@
using GeneXus.Services;
using GeneXus.Utils;
using GxClasses.Helpers;
-using log4net;
namespace GeneXus.Messaging.Common
{
[GXApi]
public class MessageQueueProvider : SimpleMessageQueue
{
- static readonly ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
private static GXService providerService;
- public MessageQueueProvider()
- {
-
+ public MessageQueueProvider(){
}
public SimpleMessageQueue Connect(string providerTypeName, GXProperties properties, out GXBaseCollection errorMessages, out bool success)
@@ -69,30 +66,30 @@ public SimpleMessageQueue Connect(string providerTypeName, GXProperties properti
return (simpleMessageQueue);
}
- private static void Preprocess(String name, GXProperties properties)
+ private static void Preprocess(string name, GXProperties properties)
{
string className;
-
switch (name)
{
case "AZUREQUEUE":
- className = "GeneXus.Messaging.Queue.AzureQueue";
- SetEncryptedProperty(properties, "QUEUE_AZUREQUEUE_QUEUENAME");
- SetEncryptedProperty(properties, "QUEUE_AZUREQUEUE_CONNECTIONSTRING");
+ className = PropertyConstants.AZURE_QUEUE_CLASSNAME;
+ SetEncryptedProperty(properties, PropertyConstants.QUEUENAME);
+ SetEncryptedProperty(properties, PropertyConstants.CONNECTIONSTRING);
+ SetEncryptedProperty(properties, PropertyConstants.QUEUEURI);
if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className))
{
- providerService.ClassName = "GeneXus.Messaging.Queue.AzureQueue, GXAzureQueue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
+ providerService.ClassName = PropertyConstants.AZURE_QUEUE_PROVIDER_CLASSNAME;
}
break;
case "AWS_SQS":
className = "GeneXus.Messaging.Queue.AWSQueue";
- SetEncryptedProperty(properties, "QUEUE_AWSSQS_QUEUE_URL");
- SetEncryptedProperty(properties, "QUEUE_AWSSQS_ACCESS_KEY");
- SetEncryptedProperty(properties, "QUEUE_AWSSQS_SECRET_KEY");
- SetEncryptedProperty(properties, "QUEUE_AWSSQS_REGION");
+ SetEncryptedProperty(properties, PropertyConstants.QUEUE_AWSSQS_QUEUE_URL);
+ SetEncryptedProperty(properties, PropertyConstants.QUEUE_AWSSQS_ACCESS_KEY);
+ SetEncryptedProperty(properties, PropertyConstants.QUEUE_AWSSQS_SECRET_KEY);
+ SetEncryptedProperty(properties, PropertyConstants.QUEUE_AWSSQS_REGION);
if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className))
{
- providerService.ClassName = "GeneXus.Messaging.Queue.AWSQueue, GXAmazonSQS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
+ providerService.ClassName = PropertyConstants.AWSSQS_QUEUE_PROVIDERTYPENAME;
}
break;
@@ -100,11 +97,11 @@ private static void Preprocess(String name, GXProperties properties)
throw new SystemException(string.Format("Provider {0} is not supported.", name));
}
}
- private static void SetEncryptedProperty(GXProperties properties, String prop)
+ private static void SetEncryptedProperty(GXProperties properties, string prop)
{
- String value = properties.Get(prop);
+ string value = properties.Get(prop);
if (string.IsNullOrEmpty(value))
- value = String.Empty;
+ value = string.Empty;
value = CryptoImpl.Encrypt(value);
properties.Set(prop, value);
}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/PropertyConstants.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/PropertyConstants.cs
new file mode 100644
index 000000000..32276b68c
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/PropertyConstants.cs
@@ -0,0 +1,35 @@
+namespace GeneXus.Messaging.Common
+{
+ public static class PropertyConstants
+ {
+ //Azure Storage Queue
+ internal const string AZURE_QUEUE_CLASSNAME = "GeneXus.Messaging.Queue.AzureQueue";
+ internal const string AZURE_QUEUE_PROVIDER_CLASSNAME = "GeneXus.Messaging.Queue.AzureQueue, GXAzureQueue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
+ public const string AZURE_QUEUE_PROVIDERTYPENAME = "AZUREQUEUE";
+
+ public const string QUEUE_SERVICE_NAME = "QUEUE";
+
+ public const string QUEUE_AZUREQUEUE_QUEUENAME = "QUEUE_AZUREQUEUE_QUEUENAME";
+ public const string QUEUE_AZUREQUEUE_CONNECTIONSTRING = "QUEUE_AZUREQUEUE_CONNECTIONSTRING";
+ public const string QUEUE_AZUREQUEUE_QUEUEURI = "QUEUE_AZUREQUEUE_QUEUEURI";
+
+ public const string QUEUENAME = "QUEUENAME";
+ public const string CONNECTIONSTRING = "CONNECTIONSTRING";
+ public const string QUEUEURI = "QUEUEURI";
+ public const string AUTHENTICATION_METHOD = "AUTHENTICATION_METHOD";
+
+ //AWS SQS
+
+ public const string AWSSQS_QUEUE_PROVIDERTYPENAME = "GeneXus.Messaging.Queue.AWSQueue, GXAmazonSQS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
+ public const string QUEUE_AWSSQS_QUEUE_URL = "QUEUE_AWSSQS_QUEUE_URL";
+ public const string QUEUE_AWSSQS_ACCESS_KEY = "QUEUE_AWSSQS_ACCESS_KEY";
+ public const string QUEUE_AWSSQS_SECRET_KEY = "QUEUE_AWSSQS_SECRET_KEY";
+ public const string QUEUE_AWSSQS_REGION = "QUEUE_AWSSQS_REGION";
+
+ }
+ public enum AuthenticationMethod
+ {
+ ActiveDirectory,
+ Password
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/QueueBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/QueueBase.cs
index d8b80fdea..6d0635494 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/QueueBase.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/QueueBase.cs
@@ -1,16 +1,11 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using GeneXus.Services;
-using log4net;
namespace GeneXus.Messaging.Common
{
public abstract class QueueBase
{
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(QueueBase));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
internal GXService service;
public QueueBase()
{
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/ServiceSettings.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/ServiceSettings.cs
deleted file mode 100644
index 443f5223e..000000000
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/ServiceSettings.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using GeneXus.Encryption;
-using GeneXus.Messaging.Common;
-using GeneXus.Services;
-using log4net;
-
-namespace GeneXus.Messaging.Queue
-{
- public class ServiceSettings
- {
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(ServiceSettings));
-
- internal GXService service;
- public string serviceNameResolver { get; }
- public string name { get; }
-
- public ServiceSettings(string serviceNameResolver, string name, GXService gXService)
- {
- this.serviceNameResolver = serviceNameResolver;
- this.name = name;
- this.service = gXService;
- }
-
- public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName = null)
- {
- String value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null);
- if (value == null)
- {
- String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
- logger.Fatal(errorMessage);
- throw new Exception(errorMessage);
- }
- return value;
- }
- public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName, string defaultValue)
- {
- String value = GetPropertyValue(propertyName, alternativePropertyName, defaultValue);
- if (!String.IsNullOrEmpty(value))
- {
- try
- {
- string ret = String.Empty;
- if (CryptoImpl.Decrypt(ref ret, value))
- {
- value = ret;
- }
- }
- catch (Exception)
- {
- logger.Warn($"Could not decrypt property name: {ResolvePropertyName(propertyName)}");
- }
- }
- return value;
- }
-
- internal string GetPropertyValue(string propertyName, string alternativePropertyName = null)
- {
- String value = GetPropertyValue(propertyName, alternativePropertyName, null);
- if (value == null)
- {
- String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined");
- logger.Fatal(errorMessage);
- throw new Exception(errorMessage);
- }
- return value;
- }
-
- internal string GetPropertyValue(string propertyName, string alternativePropertyName, string defaultValue)
- {
- String value = null;
- value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(ResolvePropertyName(propertyName)) : value;
- value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(propertyName) : value;
- value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(alternativePropertyName) : value;
- value = string.IsNullOrEmpty(value) ? defaultValue : value;
- return value;
- }
-
- internal string GetPropertyValueImpl(string propertyName)
- {
- String value = null;
- if (!string.IsNullOrEmpty(propertyName))
- {
- value = Environment.GetEnvironmentVariable(propertyName);
- if (service != null && value == null)
- {
- value = service.Properties.Get(propertyName);
- }
- }
- return value;
- }
-
- internal string ResolvePropertyName(string propertyName)
- {
- return $"{serviceNameResolver}_{name}_{propertyName}";
- }
- }
-}
diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/SimpleMessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/SimpleMessageQueue.cs
index e243ca161..18739ffda 100644
--- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/SimpleMessageQueue.cs
+++ b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/SimpleMessageQueue.cs
@@ -1,14 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.IO;
using System.Reflection;
using System.Text;
-using GeneXus.Application;
using GeneXus.Services;
using GeneXus.Utils;
using GxClasses.Helpers;
-using log4net;
namespace GeneXus.Messaging.Common
{
@@ -16,7 +13,7 @@ public class SimpleMessageQueue
{
internal IQueue queue = null;
public static Assembly assembly;
- static readonly ILog logger = log4net.LogManager.GetLogger(typeof(SimpleMessageQueue));
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
private const string SDT_MESSAGE_CLASS_NAME = @"SdtMessage";
private const string SDT_MESSAGEPROPERTY_CLASS_NAME = @"SdtMessageProperty";
private const string SDT_MESSAGERESULT_CLASS_NAME = @"SdtMessageResult";
@@ -434,7 +431,7 @@ protected void QueueErrorMessagesSetup(Exception ex, out GXBaseCollection();
public static GXServices GetGXServices()
{
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/GXOtel.Diagnostics.csproj b/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/GXOtel.Diagnostics.csproj
new file mode 100644
index 000000000..ef080b861
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/GXOtel.Diagnostics.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net8.0
+ NETCORE;
+ Properties
+ false
+ GeneXus.OpenTelemetry.Diagnostics
+ OpenTelemetry Diagnostics
+ GeneXus.OpenTelemetry.Diagnostics
+ NU1605
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/OtelSpan.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/OtelSpan.cs
new file mode 100644
index 000000000..d05c93aa8
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/OtelSpan.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Diagnostics;
+using GeneXus.Attributes;
+using OpenTelemetry;
+using OpenTelemetry.Trace;
+
+namespace GeneXus.OpenTelemetry.Diagnostics
+{
+ [GXApi]
+ public class OtelSpan
+ {
+ private Activity _activity;
+ public enum SpanStatusCode
+ {
+ Unset,
+ Ok,
+ Error
+ }
+
+ internal OtelSpan(Activity activity)
+ {
+ _activity = activity;
+ }
+
+ public OtelSpan()
+ {}
+
+ public Activity Activity => _activity;
+
+ #region EO Properties
+ public GXSpanContext SpanContext => _activity == null ? null : new GXSpanContext(_activity.Context);
+
+ public GXTraceContext GetContext => _activity == null ? null : new GXTraceContext(_activity.Context);
+ public string SpanId => _activity?.Id;
+
+ public string TraceId => _activity?.TraceId.ToHexString();
+
+ #endregion
+
+ #region Methods
+ public void Stop()
+ {
+ _activity?.Stop();
+ }
+ public void RecordException(string message)
+ {
+ _activity?.RecordException(new Exception(message));
+ }
+
+ public void SetStringAttribute(string property, string value)
+ {
+ _activity?.SetTag(property, value);
+
+ }
+ public void SetLongAttribute(string property, long value)
+ {
+ _activity?.SetTag(property, value);
+
+ }
+ public void SetDoubleAttribute(string property, double value)
+ {
+ _activity?.SetTag(property, value);
+
+ }
+ public void SetBooleanAttribute(string property, bool value)
+ {
+ _activity?.SetTag(property, value);
+
+ }
+ public GXTraceContext AddBaggage(string property, string value)
+ {
+ Baggage.SetBaggage(property, value);
+ if (_activity != null)
+ return new GXTraceContext(_activity.Context);
+ else return null;
+ }
+
+ public string GetBaggageItem(string property,GXTraceContext gXTraceContext)
+ {
+ return Baggage.GetBaggage(property);
+ }
+ public void SetStatus(SpanStatusCode spanStatusCode, string message)
+ {
+ _activity?.SetStatus((ActivityStatusCode)spanStatusCode, message);
+ }
+ public void SetStatus(SpanStatusCode spanStatusCode)
+ {
+ _activity?.SetStatus((ActivityStatusCode)spanStatusCode);
+ }
+
+ #endregion
+
+ #region Private Methods
+ public bool IsRecording => IsSpanRecording();
+
+ private bool IsSpanRecording()
+ {
+ if (_activity != null)
+ return _activity.IsAllDataRequested;
+ else
+ return false;
+ }
+ #endregion
+
+ }
+
+ public class GXTraceContext : GXSpanContext
+ {
+ //Dummy class to be compatible with Java.
+ //.NET does not requiere propagating the context explicitly in most of the cases.
+ //https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Api/README.md#baggage-api
+
+ public GXTraceContext(ActivityContext activityContext):base(activityContext) { }
+ public GXTraceContext():base() { }
+ }
+ public class GXSpanContext
+ {
+ private ActivityContext _activityContext;
+ public GXSpanContext()
+ {
+ _activityContext = Activity.Current.Context;
+ }
+
+ public GXSpanContext(ActivityContext activityContext)
+ {
+ _activityContext = activityContext;
+ }
+ public ActivityContext ActivityContext { get { return _activityContext; } }
+
+ public string TraceId => GetTraceId();
+
+ public string SpanId => GetSpanId();
+
+ private string GetTraceId()
+ {
+ if (_activityContext != null)
+ {
+ ActivityTraceId activityTraceId = _activityContext.TraceId;
+ return activityTraceId.ToHexString();
+ } else return null;
+ }
+ private string GetSpanId()
+ {
+ if (_activityContext != null)
+ {
+ ActivitySpanId activitySpanId = _activityContext.SpanId;
+ return activitySpanId.ToHexString();
+ } else { return null; }
+ }
+ private GXActivityTraceFlags TraceFlags()
+ {
+ if (_activityContext != null) {
+ ActivityTraceFlags activityTraceFlags = _activityContext.TraceFlags;
+ return (GXActivityTraceFlags)activityTraceFlags;
+ }
+ else { return GXActivityTraceFlags.None;}
+ }
+
+ private string TraceState()
+ {
+ if (_activityContext != null)
+ return _activityContext.TraceState;
+ else return null;
+ }
+
+
+ //
+ // Summary:
+ // Specifies flags defined by the W3C standard that are associated with an activity.
+
+ internal enum GXActivityTraceFlags
+ {
+ //
+ // Summary:
+ // The activity has not been marked.
+ None = 0,
+ //
+ // Summary:
+ // The activity (or more likely its parents) has been marked as useful to record.
+ Recorded = 1
+ }
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/OtelTracer.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/OtelTracer.cs
new file mode 100644
index 000000000..812b1ae28
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/Diagnostics/GXOtel.Diagnostics/OtelTracer.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using GeneXus.Attributes;
+using GeneXus.Services.OpenTelemetry;
+
+namespace GeneXus.OpenTelemetry.Diagnostics
+{
+ [GXApi]
+ public class OtelTracer
+ {
+ internal static ActivitySource activitySource;
+ internal static ActivitySource ActivitySource
+ {
+ get
+ {
+ if (activitySource == null)
+ {
+ activitySource = string.IsNullOrEmpty(OpenTelemetryService.GX_ACTIVITY_SOURCE_VERSION) ? new(OpenTelemetryService.GX_ACTIVITY_SOURCE_NAME) : new(OpenTelemetryService.GX_ACTIVITY_SOURCE_NAME, OpenTelemetryService.GX_ACTIVITY_SOURCE_VERSION);
+ }
+ return activitySource;
+ }
+ }
+ public enum SpanType
+ {
+ Internal,
+ Server,
+ Client,
+ Producer,
+ Consumer
+ }
+
+ public OtelSpan CreateSpan(string name)
+ {
+ //Returns null when the are no listeners.
+ Activity activity = ActivitySource.StartActivity(name);
+ if (activity != null)
+ return new OtelSpan(activity);
+ return null;
+ }
+
+ public OtelSpan CreateSpan(string name, SpanType kind)
+ {
+ Activity activity = ActivitySource.StartActivity(name, (ActivityKind)kind);
+ if (activity != null)
+ return new OtelSpan(activity);
+ else
+ return null;
+ }
+
+ public OtelSpan CreateSpan(string name, GXTraceContext gxTraceContext, SpanType spanType)
+ {
+ Activity activity = ActivitySource.StartActivity(name,
+ kind: (ActivityKind)spanType,
+ parentContext: gxTraceContext.ActivityContext);
+ return new OtelSpan(activity);
+
+ }
+
+ public OtelSpan CreateSpan(string name, GXTraceContext gxTraceContext, SpanType spanType, IList gxSpanContexts)
+ {
+ //https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs#optional-links
+ List contexts = new List();
+
+ foreach (GXSpanContext gxSpanContext in gxSpanContexts)
+ {
+ ActivityContext context = gxSpanContext.ActivityContext;
+ contexts.Add(context);
+ }
+
+ Activity activity = ActivitySource.StartActivity(name,
+ kind: (ActivityKind)spanType,
+ parentContext: gxTraceContext.ActivityContext,
+ links: contexts.Select(ctx => new ActivityLink(ctx)));
+ return new OtelSpan(activity);
+ }
+
+ public OtelSpan CreateSpan(string name, GXTraceContext gxTraceContext, SpanType spanType, IList gxSpanContexts, DateTime dateTime)
+ {
+ //https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs#optional-links
+ List contexts = new List();
+
+ foreach (GXSpanContext gxSpanContext in gxSpanContexts)
+ {
+ ActivityContext context = gxSpanContext.ActivityContext;
+ contexts.Add(context);
+ }
+
+ Activity activity = ActivitySource.StartActivity(name,
+ kind: (ActivityKind)spanType,
+ parentContext: gxTraceContext.ActivityContext,
+ links: contexts.Select(ctx => new ActivityLink(ctx)),
+ startTime:dateTime);
+ return new OtelSpan(activity);
+ }
+
+ public static OtelSpan GetCurrent()
+ {
+ return new OtelSpan(Activity.Current);
+ }
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GXMeterProviderBuilder.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GXMeterProviderBuilder.cs
new file mode 100644
index 000000000..0e5630c85
--- /dev/null
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GXMeterProviderBuilder.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+
+namespace GeneXus.OpenTelemetry
+{
+ public static class GXMeterProviderBuilder
+ {
+ public static MeterProviderBuilder AddGxMeterAspNetInstrumentation(this MeterProviderBuilder meter)
+ {
+ string envvar = Environment.GetEnvironmentVariable("OTEL_METRICS_EXPORTER");
+ meter
+ .AddAspNetCoreInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddRuntimeInstrumentation()
+ .AddOtlpExporter();
+ if (envvar != null && envvar.Contains("console"))
+ meter.AddConsoleExporter();
+ return meter;
+ }
+
+ }
+}
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GeneXus.OpenTelemetry.csproj b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GeneXus.OpenTelemetry.csproj
index 1564bc6e3..64f9fc9ee 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GeneXus.OpenTelemetry.csproj
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GeneXus.OpenTelemetry.csproj
@@ -1,21 +1,20 @@
-
- net6.0
- enable
- enable
- GeneXus.OpenTelemetry
- OpenTelemetry GeneXus DotNet
- GeneXus.OpenTelemetry.OpenTelemetry
- NU1605
-
+
+ net6.0;net8.0
+ GeneXus.OpenTelemetry
+ OpenTelemetry GeneXus DotNet
+ GeneXus.OpenTelemetry.OpenTelemetry
+ NU1605
+
-
-
-
-
-
+
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GxTraceProviderBuilder.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GxTraceProviderBuilder.cs
index 58da3b8d2..124a86da6 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GxTraceProviderBuilder.cs
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/GxTraceProviderBuilder.cs
@@ -1,3 +1,4 @@
+using System;
using GeneXus.Services.OpenTelemetry;
using OpenTelemetry.Trace;
@@ -19,17 +20,15 @@ public static TracerProviderBuilder AddGxAspNetInstrumentation(this TracerProvid
{
opt.RecordException = true;
})
- .AddAspNetCoreInstrumentation(opt =>
- {
- opt.RecordException = true;
- })
.AddSqlClientInstrumentation(opt =>
{
opt.RecordException = true;
opt.EnableConnectionLevelAttributes = true;
opt.SetDbStatementForText = true;
- })
- .AddConsoleExporter();
+ });
+ string envvar = Environment.GetEnvironmentVariable("OTEL_TRACES_EXPORTER");
+ if (envvar != null && envvar.Contains("console"))
+ tracer.AddConsoleExporter();
return tracer;
}
}
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/OpenTelemetryProvider.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/OpenTelemetryProvider.cs
index 78eaf649e..c7c237dcf 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/OpenTelemetryProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetry/OpenTelemetryProvider.cs
@@ -2,23 +2,41 @@
using GeneXus.Services.OpenTelemetry;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Trace;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using System;
+using Microsoft.IdentityModel.Tokens;
namespace GeneXus.OpenTelemetry.OpenTelemetry
{
public class OpenTelemetryProvider : IOpenTelemetryProvider
{
+ const string OTEL_METRICS_EXPORTER = "OTEL_METRICS_EXPORTER";
+ const string OTEL_TRACES_EXPORTER = "OTEL_TRACES_EXPORTER";
public OpenTelemetryProvider(GXService s)
{
}
public bool InstrumentAspNetCoreApplication(IServiceCollection services)
{
- services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
- {
- tracerProviderBuilder
- .AddOtlpExporter()
- .AddGxAspNetInstrumentation();
- });
+ string envvar = Environment.GetEnvironmentVariable(OTEL_TRACES_EXPORTER);
+ if (envvar.IsNullOrEmpty() || !envvar.ToLower().Equals("none")) {
+ services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
+ {
+ tracerProviderBuilder
+ .AddOtlpExporter()
+ .AddGxAspNetInstrumentation();
+ });
+ }
+
+ envvar = Environment.GetEnvironmentVariable(OTEL_METRICS_EXPORTER);
+ if (envvar.IsNullOrEmpty() || !envvar.ToLower().Equals("none")) {
+ services.AddOpenTelemetry().WithMetrics(metricsProviderBuilder =>
+ {
+ metricsProviderBuilder
+ .AddGxMeterAspNetInstrumentation();
+ });
+ }
return true;
}
}
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/AWSOtelProvider.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/AWSOtelProvider.cs
index 2aae5321f..7de8b29f1 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/AWSOtelProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/AWSOtelProvider.cs
@@ -1,12 +1,11 @@
using System;
+using GeneXus.Services;
using GeneXus.Services.OpenTelemetry;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry;
-using OpenTelemetry.Trace;
using OpenTelemetry.Contrib.Extensions.AWSXRay.Trace;
-using GeneXus.Services;
-using GeneXus.Services.Common;
-using GeneXus.Diagnostics;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
namespace GeneXus.OpenTelemetry.AWS
{
@@ -33,6 +32,10 @@ public bool InstrumentAspNetCoreApplication(IServiceCollection _)
.AddGxAspNetInstrumentation()
.Build();
+ Sdk.CreateMeterProviderBuilder()
+ .AddGxMeterAspNetInstrumentation()
+ .Build();
+
Sdk.SetDefaultTextMapPropagator(new AWSXRayPropagator());
return true;
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/GeneXus.OpenTelemetry.AWS.AspNet.csproj b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/GeneXus.OpenTelemetry.AWS.AspNet.csproj
index 2fe0c462b..1fb368fc7 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/GeneXus.OpenTelemetry.AWS.AspNet.csproj
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAWSOtel/GeneXus.OpenTelemetry.AWS.AspNet.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net6.0;net8.0
NETCORE;
Properties
false
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/AzureAppInsights.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/AzureAppInsights.cs
index 68e6152ae..96c804a64 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/AzureAppInsights.cs
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/AzureAppInsights.cs
@@ -1,39 +1,68 @@
using System;
-using Azure.Monitor.OpenTelemetry.AspNetCore;
+using Azure.Identity;
+using Azure.Monitor.OpenTelemetry.Exporter;
using GeneXus.Services;
using GeneXus.Services.OpenTelemetry;
-using log4net;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+using OpenTelemetry.Logs;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
namespace GeneXus.OpenTelemetry.Azure
{
public class AzureAppInsights : IOpenTelemetryProvider
{
- private static readonly ILog log = LogManager.GetLogger(typeof(AzureAppInsights));
+ private static readonly IGXLogger log = GXLoggerFactory.GetLogger();
private const string APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING";
public AzureAppInsights(GXService s)
{
}
- public bool InstrumentAspNetCoreApplication(IServiceCollection services)
+ public bool InstrumentAspNetCoreApplication(IServiceCollection _)
{
string oltpEndpoint = Environment.GetEnvironmentVariable(APPLICATIONINSIGHTS_CONNECTION_STRING);
-
- if (!string.IsNullOrEmpty(oltpEndpoint))
+ try
{
- services.AddOpenTelemetry()
- .UseAzureMonitor( o =>
- {
+ var resourceBuilder = ResourceBuilder.CreateDefault()
+ .AddTelemetrySdk();
+
+ Sdk.CreateTracerProviderBuilder()
+ .SetResourceBuilder(resourceBuilder)
+ .AddAzureMonitorTraceExporter(o =>
+ {
+ if (!string.IsNullOrEmpty(oltpEndpoint))
o.ConnectionString = oltpEndpoint;
- });
+ else
+ {
+ o.Credential = new DefaultAzureCredential();
+ GXLogging.Debug(log, "Connect to Azure monitor Opentelemetry Trace exporter using Default Azure credential");
+ }
+ })
+ .AddGxAspNetInstrumentation()
+ .Build();
+ Sdk.CreateMeterProviderBuilder()
+ .SetResourceBuilder(resourceBuilder)
+ .AddAzureMonitorMetricExporter(o =>
+ {
+ if (!string.IsNullOrEmpty(oltpEndpoint))
+ o.ConnectionString = oltpEndpoint;
+ else
+ {
+ o.Credential = new DefaultAzureCredential();
+ GXLogging.Debug(log, "Connect to Azure monitor Opentelemetry Metrics exporter using Default Azure credential");
+ }
+ })
+ .AddGxMeterAspNetInstrumentation()
+ .Build();
return true;
}
- else
- {
- log.Warn("OpenTelemetry Azure Monitor was not initialized due to missing 'APPLICATIONINSIGHTS_CONNECTION_STRING' Environment Variable");
+ catch (Exception ex)
+ {
+ GXLogging.Warn(log, "Azure Monitor Opentelemetry could not be initialized. " + ex.Message);
return false;
}
}
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/GeneXus.OpenTelemetry.Azure.AppInsights.csproj b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/GeneXus.OpenTelemetry.Azure.AppInsights.csproj
index f8d09b91f..b627b6bd5 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/GeneXus.OpenTelemetry.Azure.AppInsights.csproj
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryAzureMonitor/GeneXus.OpenTelemetry.Azure.AppInsights.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
NETCORE;
Properties
false
@@ -10,7 +10,15 @@
NU1605
-
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/GeneXus.OpenTelemetry.Lightstep.AspNet.csproj b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/GeneXus.OpenTelemetry.Lightstep.AspNet.csproj
index 5702ecd91..6114b9112 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/GeneXus.OpenTelemetry.Lightstep.AspNet.csproj
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/GeneXus.OpenTelemetry.Lightstep.AspNet.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net6.0;net8.0
NETCORE;
Properties
false
diff --git a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/LightstepProvider.cs b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/LightstepProvider.cs
index 228b579ff..8d251d1c8 100644
--- a/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/LightstepProvider.cs
+++ b/dotnet/src/dotnetcore/Providers/OpenTelemetry/OpenTelemetryLightStep/LightstepProvider.cs
@@ -1,19 +1,16 @@
using System;
+using GeneXus.Services;
using GeneXus.Services.OpenTelemetry;
using Microsoft.Extensions.DependencyInjection;
-using OpenTelemetry;
using OpenTelemetry.Trace;
-using OpenTelemetry.Resources;
-using log4net;
-using GeneXus.Services;
namespace GeneXus.OpenTelemetry.Lightstep
{
public class LightStepOpenTelemetry : IOpenTelemetryProvider
{
- private static readonly ILog log = LogManager.GetLogger(typeof(LightStepOpenTelemetry));
+ static readonly IGXLogger log = GXLoggerFactory.GetLogger();
private const string LIGHTSTEP_INGREST_URL = "ingest.lightstep.com:443";
private const string LIGHTSTEP_ACCESS_TOKEN = "LS_ACCESS_TOKEN";
@@ -27,7 +24,7 @@ public bool InstrumentAspNetCoreApplication(IServiceCollection services)
if (string.IsNullOrEmpty(lightstepToken))
{
- log.Warn("OpenTelemetry Lightstep was not initialized due to missing 'LS_ACCESS_TOKEN' Environment Variable");
+ GXLogging.Warn(log, "OpenTelemetry Lightstep was not initialized due to missing 'LS_ACCESS_TOKEN' Environment Variable");
return false;
}
diff --git a/dotnet/src/dotnetcore/Providers/Storage/GXAmazonS3/GXAmazonS3.csproj b/dotnet/src/dotnetcore/Providers/Storage/GXAmazonS3/GXAmazonS3.csproj
index 2f83482a0..ca162324b 100644
--- a/dotnet/src/dotnetcore/Providers/Storage/GXAmazonS3/GXAmazonS3.csproj
+++ b/dotnet/src/dotnetcore/Providers/Storage/GXAmazonS3/GXAmazonS3.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
TRACE;DEBUG;NETCORE
Properties
false
@@ -13,6 +13,7 @@
+
diff --git a/dotnet/src/dotnetcore/Providers/Storage/GXAzureStorage/GXAzureStorage.csproj b/dotnet/src/dotnetcore/Providers/Storage/GXAzureStorage/GXAzureStorage.csproj
index 2e414d14e..62f614c32 100644
--- a/dotnet/src/dotnetcore/Providers/Storage/GXAzureStorage/GXAzureStorage.csproj
+++ b/dotnet/src/dotnetcore/Providers/Storage/GXAzureStorage/GXAzureStorage.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net6.0;net8.0
TRACE;DEBUG;NETCORE
Properties
false
@@ -15,6 +15,7 @@
+
diff --git a/dotnet/src/dotnetcore/Providers/Storage/GXGoogleCloud/GXGoogleCloud.csproj b/dotnet/src/dotnetcore/Providers/Storage/GXGoogleCloud/GXGoogleCloud.csproj
index f036cd022..1af8b36e6 100644
--- a/dotnet/src/dotnetcore/Providers/Storage/GXGoogleCloud/GXGoogleCloud.csproj
+++ b/dotnet/src/dotnetcore/Providers/Storage/GXGoogleCloud/GXGoogleCloud.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
TRACE;DEBUG;NETCORE
Properties
false
@@ -14,6 +14,7 @@
+
diff --git a/dotnet/src/dotnetcore/Reor/Reor.csproj b/dotnet/src/dotnetcore/Reor/Reor.csproj
index f02fc7005..7743e4090 100644
--- a/dotnet/src/dotnetcore/Reor/Reor.csproj
+++ b/dotnet/src/dotnetcore/Reor/Reor.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net6.0;net8.0
Exe
Reorg
GeneXus.Reorganization.Core
@@ -16,14 +16,18 @@
+
+
+
+
- contentFiles/any/any
+ contentFiles/any/$(TargetFramework)
true
- contentFiles/any/any
+ contentFiles/any/$(TargetFramework)
true
diff --git a/dotnet/src/dotnetcore/libs/net8.0/Jayrock.dll b/dotnet/src/dotnetcore/libs/net8.0/Jayrock.dll
new file mode 100644
index 000000000..fd1736afd
Binary files /dev/null and b/dotnet/src/dotnetcore/libs/net8.0/Jayrock.dll differ
diff --git a/dotnet/src/dotnetframework/DynServiceOData/DynServiceOData.csproj b/dotnet/src/dotnetframework/DynServiceOData/DynServiceOData.csproj
index 7ef6d238e..2cf30c8fd 100644
--- a/dotnet/src/dotnetframework/DynServiceOData/DynServiceOData.csproj
+++ b/dotnet/src/dotnetframework/DynServiceOData/DynServiceOData.csproj
@@ -11,7 +11,6 @@
-
diff --git a/dotnet/src/dotnetframework/GxClasses.Win/GxClasses.Win.csproj b/dotnet/src/dotnetframework/GxClasses.Win/GxClasses.Win.csproj
index 1d113bc5d..bdff5e121 100644
--- a/dotnet/src/dotnetframework/GxClasses.Win/GxClasses.Win.csproj
+++ b/dotnet/src/dotnetframework/GxClasses.Win/GxClasses.Win.csproj
@@ -8,11 +8,10 @@
GeneXus.Classes.Win
-
-
+
\ No newline at end of file
diff --git a/dotnet/src/dotnetframework/GxClasses.Win/Process/CommandLine.cs b/dotnet/src/dotnetframework/GxClasses.Win/Process/CommandLine.cs
index ad02258b6..b43620759 100644
--- a/dotnet/src/dotnetframework/GxClasses.Win/Process/CommandLine.cs
+++ b/dotnet/src/dotnetframework/GxClasses.Win/Process/CommandLine.cs
@@ -1,8 +1,7 @@
-using GeneXus.Application;
-using log4net;
using System;
using System.Diagnostics;
using System.IO;
+using GeneXus.Application;
namespace GeneXus.Utils
{
@@ -19,8 +18,7 @@ public IProcessHelper GetProcessHelper()
}
public class GxProcess : IProcessHelper
{
- static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.Utils.GxProcess));
-
+ static readonly IGXLogger log = GXLoggerFactory.GetLogger();
public short OpenPrintDocument(string commandString)
{
Process p = new Process();
diff --git a/dotnet/src/dotnetframework/GxClasses/Configuration/ExternalStorage.cs b/dotnet/src/dotnetframework/GxClasses/Configuration/ExternalStorage.cs
index f7433d04c..6357186e2 100644
--- a/dotnet/src/dotnetframework/GxClasses/Configuration/ExternalStorage.cs
+++ b/dotnet/src/dotnetframework/GxClasses/Configuration/ExternalStorage.cs
@@ -3,7 +3,6 @@
using GeneXus.Attributes;
using GeneXus.Utils;
using GeneXus.Encryption;
-using log4net;
#if NETCORE
using GxClasses.Helpers;
#endif
@@ -16,8 +15,7 @@ public class ExternalStorage : GxStorageProvider
private GXService providerService;
- static readonly ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
-
+ static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
public ExternalStorage()
{
@@ -59,7 +57,7 @@ public bool Create(string name, GXProperties properties, ref GxStorageProvider s
}
string typeFullName = providerService.ClassName;
- logger.Debug("Loading storage provider: "+ typeFullName);
+ GXLogging.Debug(logger, "Loading storage provider: " + typeFullName);
#if !NETCORE
Type type = Type.GetType(typeFullName, true, true);
#else
@@ -70,7 +68,7 @@ public bool Create(string name, GXProperties properties, ref GxStorageProvider s
}
catch (Exception ex)
{
- logger.Error("Couldn't connect to external storage provider. ", ex);
+ GXLogging.Error(logger, "Couldn't connect to external storage provider. ", ex);
StorageMessages(ex, messages);
return false;
}
diff --git a/dotnet/src/dotnetframework/GxClasses/Configuration/LogConfiguration.cs b/dotnet/src/dotnetframework/GxClasses/Configuration/LogConfiguration.cs
index 43495ecf7..69428b857 100644
--- a/dotnet/src/dotnetframework/GxClasses/Configuration/LogConfiguration.cs
+++ b/dotnet/src/dotnetframework/GxClasses/Configuration/LogConfiguration.cs
@@ -1,17 +1,16 @@
using System;
+using System.Linq;
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Repository;
using log4net.Repository.Hierarchy;
-using System.Linq;
-using log4net.Layout;
namespace GeneXus.Configuration
{
internal class LogConfiguration
{
- private static readonly ILog logger = log4net.LogManager.GetLogger(typeof(LogConfiguration));
+ //private static readonly IGXLogger logger = GXLoggerFactory.GetLogger();
public const string USER_LOG_TOPIC = "GeneXusUserLog";
private const string LOG_LEVEL_ENVVAR = "GX_LOG_LEVEL";
@@ -20,7 +19,11 @@ internal class LogConfiguration
public static void SetupLog4Net()
{
- SetupLog4NetFromEnvironmentVariables();
+ Config.GetValueOf("LOG_OUTPUT", out string logProvider);
+ if (logProvider == "ASPNetTraceAppender" || logProvider == "ConsoleAppender" || logProvider == "EventLogAppender" || logProvider == "RollingFile")
+ {
+ SetupLog4NetFromEnvironmentVariables();
+ }
}
private static void SetupLog4NetFromEnvironmentVariables()
@@ -53,10 +56,10 @@ private static void SetupLog4NetFromEnvironmentVariables()
if (!String.IsNullOrEmpty(appenderName))
{
Hierarchy h = (Hierarchy) LogManager.GetRepository();
- IAppender appenderToAdd = h.GetAppenders().First(a => a.Name == appenderName);
+ IAppender appenderToAdd = h.GetAppenders().FirstOrDefault(a => a.Name == appenderName);
if (appenderToAdd == null)
{
- LogConfiguration.logger.Error($"Appender '{appenderName}' was not found on Log4Net Config file");
+ //LogConfiguration.logger.Warn($"Appender '{appenderName}' was not found on Log4Net Config file");
return;
}
diff --git a/dotnet/src/dotnetframework/GxClasses/Core/GXApplication.cs b/dotnet/src/dotnetframework/GxClasses/Core/GXApplication.cs
index 27eed1ebf..82b3a5cce 100644
--- a/dotnet/src/dotnetframework/GxClasses/Core/GXApplication.cs
+++ b/dotnet/src/dotnetframework/GxClasses/Core/GXApplication.cs
@@ -13,6 +13,7 @@ namespace GeneXus.Application
using System.Messaging;
using System.ServiceModel.Web;
using GeneXus.UserControls;
+ using System.Net.Http.Headers;
#else
using Microsoft.AspNetCore.Http;
using GxClasses.Helpers;
@@ -20,8 +21,9 @@ namespace GeneXus.Application
#endif
using GeneXus.Configuration;
using GeneXus.Metadata;
- using log4net;
+#if !NETCORE
using Jayrock.Json;
+#endif
using GeneXus.Http;
using System.Collections.Specialized;
using System.Collections.Generic;
@@ -43,10 +45,12 @@ namespace GeneXus.Application
using Microsoft.AspNetCore.Http.Features;
#endif
using NodaTime;
- using NodaTime.TimeZones;
using System.Threading;
using System.Security.Claims;
using System.Security;
+ using Microsoft.Net.Http.Headers;
+ using System.Threading.Tasks;
+ using GeneXus.Data.ADO;
public interface IGxContext
{
@@ -291,18 +295,18 @@ public GxHttpContextAccesor(IHttpContextAccessor ctxAccessor)
public override IFeatureCollection Features => ctxAccessor.HttpContext.Features;
- public override IDictionary