Neue Features, Optimierungen und Bugfixes

- Neues Projekt `EDMI.API` zur Solution hinzugefügt.
- `App.config`: Abhängigkeiten und `bindingRedirect` aktualisiert.
- Verbesserte Thread-Sicherheit mit `ReaderWriterLockSlim`.
- SQL-Abfragen mit `WITH (NOLOCK)` für bessere Parallelität.
- Robuste Verarbeitung von `DataRow`-Werten mit `IIf(IsDBNull(...))`.
- Neue Sicherheitsprüfung für `JobListener` initialisiert.
- `SaveDataTables` optimiert, Performance-Warnungen hinzugefügt.
- Versionsnummer auf `2.5.0.0` aktualisiert, Copyright auf 2026.
- Paket `NLog` aus `packages.config` entfernt.
This commit is contained in:
Developer01
2026-08-28 12:19:34 +02:00
parent 9d5e022562
commit 0f9e7c55ec
15 changed files with 292 additions and 175 deletions

View File

@@ -74,6 +74,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DBCleaner", "DBCleaner\DBCl
EndProject EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EDMIService.Tests", "EDMIService.Tests\EDMIService.Tests.vbproj", "{E3DA65CA-964D-4896-991A-B5426884E215}" Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EDMIService.Tests", "EDMIService.Tests\EDMIService.Tests.vbproj", "{E3DA65CA-964D-4896-991A-B5426884E215}"
EndProject EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EDMI.API", "..\DDModules\EDMIAPI\EDMI.API.vbproj", "{25017513-0D97-49D3-98D7-BA76D9B251B0}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -180,6 +182,10 @@ Global
{E3DA65CA-964D-4896-991A-B5426884E215}.Debug|Any CPU.Build.0 = Debug|Any CPU {E3DA65CA-964D-4896-991A-B5426884E215}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3DA65CA-964D-4896-991A-B5426884E215}.Release|Any CPU.ActiveCfg = Release|Any CPU {E3DA65CA-964D-4896-991A-B5426884E215}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3DA65CA-964D-4896-991A-B5426884E215}.Release|Any CPU.Build.0 = Release|Any CPU {E3DA65CA-964D-4896-991A-B5426884E215}.Release|Any CPU.Build.0 = Release|Any CPU
{25017513-0D97-49D3-98D7-BA76D9B251B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25017513-0D97-49D3-98D7-BA76D9B251B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25017513-0D97-49D3-98D7-BA76D9B251B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25017513-0D97-49D3-98D7-BA76D9B251B0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -33,7 +33,7 @@
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="GdPicture.NET.14" publicKeyToken="f52a2e60ad468dbb" culture="neutral" /> <assemblyIdentity name="GdPicture.NET.14" publicKeyToken="f52a2e60ad468dbb" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-14.2.90.0" newVersion="14.2.90.0" /> <bindingRedirect oldVersion="0.0.0.0-14.3.3.0" newVersion="14.3.3.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="protobuf-net" publicKeyToken="257b51d87d2e4d67" culture="neutral" /> <assemblyIdentity name="protobuf-net" publicKeyToken="257b51d87d2e4d67" culture="neutral" />
@@ -75,6 +75,14 @@
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> <assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.5" newVersion="8.0.0.5" /> <bindingRedirect oldVersion="0.0.0.0-8.0.0.5" newVersion="8.0.0.5" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="GdPicture.NET.14.Common" publicKeyToken="f52a2e60ad468dbb" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-14.3.3.0" newVersion="14.3.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="GdPicture.NET.14.Imaging" publicKeyToken="f52a2e60ad468dbb" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-14.3.3.0" newVersion="14.3.3.0" />
</dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
</configuration> </configuration>

View File

@@ -3,8 +3,7 @@ Imports System.ServiceModel
Imports System.ServiceModel.Description Imports System.ServiceModel.Description
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language 'Imports DigitalData.Modules.
Imports DigitalData.Modules
Imports DigitalData.Modules.EDMI Imports DigitalData.Modules.EDMI
Imports DigitalData.Modules.EDMI.API.Rights Imports DigitalData.Modules.EDMI.API.Rights
Imports DigitalData.Services.EDMIService.Messages Imports DigitalData.Services.EDMIService.Messages
@@ -13,6 +12,7 @@ Imports DigitalData.Services.EDMIService.Methods
Imports DigitalData.Services.EDMIService.Methods.Database Imports DigitalData.Services.EDMIService.Methods.Database
Imports DigitalData.Services.EDMIService.Methods.IDB Imports DigitalData.Services.EDMIService.Methods.IDB
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession)> <ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession)>
Public Class EDMIService Public Class EDMIService
Implements IEDMIService Implements IEDMIService
@@ -22,7 +22,6 @@ Public Class EDMIService
Public Shared MSSQL_IDB As MSSQLServer Public Shared MSSQL_IDB As MSSQLServer
Public Shared Firebird As Firebird Public Shared Firebird As Firebird
Public Shared AppConfig As Config Public Shared AppConfig As Config
Public Shared Filesystem As Filesystem.File
Public Shared GlobalState As GlobalState Public Shared GlobalState As GlobalState
Public Shared Scheduler As Scheduler Public Shared Scheduler As Scheduler
@@ -586,7 +585,17 @@ Public Class EDMIService
Dim oRow As DataRow = oRows.First() Dim oRow As DataRow = oRows.First()
Dim oRightAsInt = oRow.Item("ACCESSRIGHT") Dim oRightAsInt = oRow.Item("ACCESSRIGHT")
oRight = Utils.ToEnum(Of AccessRight)(oRightAsInt) Select Case oRight
Case 1
oRight = AccessRight.VIEW_ONLY
Case 2
oRight = AccessRight.VIEW_EXPORT
Case 4
oRight = AccessRight.FULL
Case Else
_Logger.Warn("GetAccessRightForObjectId: Unknown access right [{0}] for user [{1}] on object [{2}]", oRightAsInt, UserId, ObjectId)
oRight = AccessRight.VIEW_ONLY
End Select
End If End If
_Logger.Debug("Successfully parsed AccessRights for ObjectId [{0}]", ObjectId) _Logger.Debug("Successfully parsed AccessRights for ObjectId [{0}]", ObjectId)

View File

@@ -79,7 +79,7 @@
<HintPath>..\..\DDModules\EDMIAPI\bin\Debug\DigitalData.Modules.EDMI.API.dll</HintPath> <HintPath>..\..\DDModules\EDMIAPI\bin\Debug\DigitalData.Modules.EDMI.API.dll</HintPath>
</Reference> </Reference>
<Reference Include="DigitalData.Modules.Filesystem"> <Reference Include="DigitalData.Modules.Filesystem">
<HintPath>P:\Projekte DIGITAL DATA\DIGITAL DATA - Entwicklung\DLL_Bibliotheken\Digital Data\DigitalData.Modules.Filesystem.dll</HintPath> <HintPath>..\..\DDModules\Filesystem\bin\Debug\DigitalData.Modules.Filesystem.dll</HintPath>
</Reference> </Reference>
<Reference Include="DigitalData.Modules.Language"> <Reference Include="DigitalData.Modules.Language">
<HintPath>P:\Projekte DIGITAL DATA\DIGITAL DATA - Entwicklung\DLL_Bibliotheken\Digital Data\DigitalData.Modules.Language.dll</HintPath> <HintPath>P:\Projekte DIGITAL DATA\DIGITAL DATA - Entwicklung\DLL_Bibliotheken\Digital Data\DigitalData.Modules.Language.dll</HintPath>

View File

@@ -1,7 +1,6 @@
Imports System.Data.SqlClient Imports System.Data.SqlClient
Imports System.Runtime.Serialization Imports System.Runtime.Serialization
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Language
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Public Class GlobalState Public Class GlobalState
@@ -13,8 +12,9 @@ Public Class GlobalState
Public Property ObjectStores As New List(Of ObjectStore) Public Property ObjectStores As New List(Of ObjectStore)
Public Property Connections As New List(Of DatabaseConnection) Public Property Connections As New List(Of DatabaseConnection)
Public Property Doctypes As New List(Of Doctype) Public Property Doctypes As New List(Of Doctype)
Public Property ClientConfig As ClientConfiguration = New ClientConfiguration()
Public Property ClientConfig As New ClientConfiguration Public Property JobListener As JobListener
Public Property TableStore As New DataSet Public Property TableStore As New DataSet
@@ -123,7 +123,7 @@ Public Class GlobalState
Public Sub LoadConnections() Public Sub LoadConnections()
_Logger.Info("Loading Database Connections") _Logger.Info("Loading Database Connections")
Try Try
Dim oSQL As String = "SELECT * FROM TBDD_CONNECTION" Dim oSQL As String = "SELECT * FROM TBDD_CONNECTION WITH (NOLOCK)"
Dim oTable As DataTable = _MSSQL_ECM.GetDatatable(oSQL) Dim oTable As DataTable = _MSSQL_ECM.GetDatatable(oSQL)
_Logger.Info("Found [{0}] Connections", oTable.Rows.Count) _Logger.Info("Found [{0}] Connections", oTable.Rows.Count)
@@ -132,14 +132,14 @@ Public Class GlobalState
For Each oRow As DataRow In oTable.Rows For Each oRow As DataRow In oTable.Rows
Dim oConnection As New DatabaseConnection() With { Dim oConnection As New DatabaseConnection() With {
.Id = oRow.ItemEx(Of Integer)("GUID"), .Id = IIf(IsDBNull(oRow.Item("GUID")), 0, oRow.Item("GUID")),
.Active = oRow.ItemEx(Of Boolean)("AKTIV"), .Active = IIf(IsDBNull(oRow.Item("AKTIV")), False, oRow.Item("AKTIV")),
.Database = oRow.ItemEx(Of String)("DATENBANK"), .Database = IIf(IsDBNull(oRow.Item("DATENBANK")), String.Empty, oRow.Item("DATENBANK")),
.Title = oRow.ItemEx(Of String)("BEZEICHNUNG"), .Title = IIf(IsDBNull(oRow.Item("BEZEICHNUNG")), String.Empty, oRow.Item("BEZEICHNUNG")),
.Password = oRow.ItemEx(Of String)("PASSWORD"), .Password = IIf(IsDBNull(oRow.Item("PASSWORD")), String.Empty, oRow.Item("PASSWORD")),
.Provider = oRow.ItemEx(Of String)("SQL_PROVIDER"), .Provider = IIf(IsDBNull(oRow.Item("SQL_PROVIDER")), String.Empty, oRow.Item("SQL_PROVIDER")),
.Server = oRow.ItemEx(Of String)("SERVER"), .Server = IIf(IsDBNull(oRow.Item("SERVER")), String.Empty, oRow.Item("SERVER")),
.Username = oRow.ItemEx(Of String)("USERNAME") .Username = IIf(IsDBNull(oRow.Item("USERNAME")), String.Empty, oRow.Item("USERNAME"))
} }
_Logger.Info("New Connection [{0}]", oConnection.Title) _Logger.Info("New Connection [{0}]", oConnection.Title)
oConnections.Add(oConnection) oConnections.Add(oConnection)

View File

@@ -1,6 +1,5 @@
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Database.MSSQLServer Imports DigitalData.Modules.Database.MSSQLServer
Imports DigitalData.Modules.Language
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Imports System.Data.SqlClient Imports System.Data.SqlClient
Imports DigitalData.Modules.ZooFlow.State Imports DigitalData.Modules.ZooFlow.State
@@ -59,8 +58,8 @@ Namespace IDB
End If End If
Dim oRow As DataRow = oTable.Rows.Item(0) Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oActive = Utils.NotNull(oRow.Item("ACTIVE"), False) Dim oActive = IIf(IsDBNull(oRow.Item("ACTIVE")), False, oRow.Item("ACTIVE"))
Dim oDeleted = Utils.NotNull(oRow.Item("DELETED"), False) Dim oDeleted = IIf(IsDBNull(oRow.Item("DELETED")), False, oRow.Item("DELETED"))
IsDeleted = oDeleted IsDeleted = oDeleted
IsActive = oActive IsActive = oActive

View File

@@ -14,49 +14,60 @@ Namespace Methods.Database.GetDatatableFromCache
Try Try
Logger.Debug($"ReturnDatatableFromCache: Datatable: {pData.DataTable}") Logger.Debug($"ReturnDatatableFromCache: Datatable: {pData.DataTable}")
Dim oDataTable As DataTable = Nothing ' ✅ NEU: Sicherheitsprüfung (sollte nie auftreten, aber defensiv)
If GlobalState.JobListener Is Nothing Then
Logger.Warn("JobListener not initialized - this should not happen! Using direct TableStore access.")
Logger.Debug("ReturnDatatableFromCache: DataSet contains [{0}] datatables", GlobalState.TableStore.Tables.Count) ' Fallback: Direkter Zugriff auf TableStore
If Not GlobalState.TableStore.Tables.Contains(pData.DataTable) Then
If GlobalState.TableStore.Tables.Contains(pData.DataTable) Then Return New GetDatatableFromCacheResponse(
oDataTable = GlobalState.TableStore.Tables.Item(pData.DataTable).Copy() New KeyNotFoundException($"Datatable {pData.DataTable} does not exist"))
' Apply filter and sorting to data
Dim oFilterExpression As String = Utils.NotNull(pData.FilterExpression, String.Empty)
Dim oSortByColumn As String = Utils.NotNull(pData.SortByColumn, String.Empty)
Logger.Debug("Applying filter expression: [{0}]", oFilterExpression)
Logger.Debug("Applying sort expression: [{0}]", oSortByColumn)
Dim oFilteredRows = oDataTable.Select(oFilterExpression, oSortByColumn)
Dim oFilteredTable As DataTable = Nothing
If oFilteredRows.Count > 0 Then
oFilteredTable = oFilteredRows.CopyToDataTable()
oFilteredTable.TableName = pData.DataTable
Else
' Produce empty table
oFilteredTable = oDataTable.Clone()
oFilteredTable.TableName = pData.DataTable
End If End If
Logger.Debug("ReturnDatatableFromCache: Datatable Stats for [{0}]:", pData.DataTable) Dim oDirectTable = GlobalState.TableStore.Tables(pData.DataTable).Copy()
Logger.Debug("Unfiltered: [{0}] rows", oDataTable.Rows.Count) ' ... Filter/Sort anwenden wie gehabt
Logger.Debug("Filtered: [{0}] rows", oFilteredTable.Rows.Count) Return New GetDatatableFromCacheResponse(ApplyFilterAndSort(oDirectTable, pData))
Return New GetDatatableFromCacheResponse(oFilteredTable)
Else
Logger.Warn($"ReturnDatatableFromCache: Datatable {pData.DataTable} does not exist")
Return New GetDatatableFromCacheResponse(New KeyNotFoundException($"Datatable {pData.DataTable} does not exist"))
End If End If
' ✅ Normal: Thread-sicheren Zugriff verwenden
Dim oDataTable As DataTable = GlobalState.JobListener.GetTableSafely(pData.DataTable)
If oDataTable Is Nothing Then
Logger.Warn($"Datatable {pData.DataTable} does not exist")
Return New GetDatatableFromCacheResponse(
New KeyNotFoundException($"Datatable {pData.DataTable} does not exist"))
End If
Return New GetDatatableFromCacheResponse(ApplyFilterAndSort(oDataTable, pData))
Catch ex As Exception Catch ex As Exception
Logger.Error(ex) Logger.Error(ex)
Return New GetDatatableFromCacheResponse(ex) Return New GetDatatableFromCacheResponse(ex)
End Try End Try
End Function End Function
' ✅ Hilfsmethode zum Filter/Sort anwenden
Private Function ApplyFilterAndSort(table As DataTable, request As GetDatatableFromCacheRequest) As DataTable
Dim oFilterExpression = IIf(IsDBNull(request.FilterExpression), String.Empty, request.FilterExpression)
Dim oSortByColumn = IIf(IsDBNull(request.SortByColumn), String.Empty, request.SortByColumn)
Logger.Debug("Filter: [{0}], Sort: [{1}]", oFilterExpression, oSortByColumn)
Dim oFilteredRows = table.Select(oFilterExpression, oSortByColumn)
Dim oResult As DataTable
If oFilteredRows.Count > 0 Then
oResult = oFilteredRows.CopyToDataTable()
Else
oResult = table.Clone()
End If
oResult.TableName = request.DataTable
Logger.Debug("Rows: {0} → {1}", table.Rows.Count, oResult.Rows.Count)
Return oResult
End Function
End Class End Class
End Namespace End Namespace

View File

@@ -37,13 +37,13 @@ Namespace Methods.GlobalIndexer
Dim oRow As DataRow = oProfile.Table.Rows.Item(0) Dim oRow As DataRow = oProfile.Table.Rows.Item(0)
Dim oProfileObject As New Profile With { Dim oProfileObject As New Profile With {
.Id = oRow.ItemEx("DOCTYPE_ID", 0), .Id = IIf(IsDBNull(oRow.Item("DOCTYPE_ID")), 0, oRow.Item("DOCTYPE_ID")),
.Name = oRow.ItemEx("DOCTYPE", "Missing Profile Name"), .Name = IIf(IsDBNull(oRow.Item("DOCTYPE")), String.Empty, oRow.Item("DOCTYPE")),
.IsActive = oRow.ItemEx("AKTIV", False), .IsActive = IIf(IsDBNull(oRow.Item("AKTIV")), False, oRow.Item("AKTIV")),
.NameConvention = oRow.ItemEx("NAMENKONVENTION", ""), .NameConvention = IIf(IsDBNull(oRow.Item("NAMENKONVENTION")), String.Empty, oRow.Item("NAMENKONVENTION")),
.ObjectStore = oRow.ItemEx("OBJECT_STORE", "Work"), .ObjectStore = IIf(IsDBNull(oRow.Item("OBJECT_STORE")), "Work", oRow.Item("OBJECT_STORE")),
.ShortName = oRow.ItemEx("KURZNAME", ""), .ShortName = IIf(IsDBNull(oRow.Item("KURZNAME")), String.Empty, oRow.Item("KURZNAME")),
.DynamicPath = oRow.ItemEx("DYNAMIC_FOLDER", "") .DynamicPath = IIf(IsDBNull(oRow.Item("DYNAMIC_FOLDER")), String.Empty, oRow.Item("DYNAMIC_FOLDER"))
} }
Logger.Debug("Name: [{0}]", oProfileObject.Name) Logger.Debug("Name: [{0}]", oProfileObject.Name)
@@ -82,13 +82,13 @@ Namespace Methods.GlobalIndexer
For Each oRow As DataRow In oAutomaticIndexes.Table.Rows For Each oRow As DataRow In oAutomaticIndexes.Table.Rows
Dim oAutomaticIndex As New AutomaticIndex With { Dim oAutomaticIndex As New AutomaticIndex With {
.Id = oRow.ItemEx(Of Integer)("GUID"), .Id = oRow.Item("GUID"),
.Name = oRow.ItemEx(Of String)("INDEXNAME"), .Name = IIf(IsDBNull(oRow.Item("INDEXNAME")), String.Empty, oRow.Item("INDEXNAME")),
.ProfileId = oRow.ItemEx(Of Integer)("DOCTYPE_ID"), .ProfileId = IIf(IsDBNull(oRow.Item("DOCTYPE_ID")), 0, oRow.Item("DOCTYPE_ID")),
.SQLCommand = oRow.ItemEx(Of String)("SQL_RESULT"), .SQLCommand = IIf(IsDBNull(oRow.Item("SQL_RESULT")), String.Empty, oRow.Item("SQL_RESULT")),
.SQLConnectionId = oRow.ItemEx(Of Integer)("CONNECTION_ID"), .SQLConnectionId = IIf(IsDBNull(oRow.Item("CONNECTION_ID")), 0, oRow.Item("CONNECTION_ID")),
.Sequence = oRow.ItemEx(Of String)("SEQUENCE"), .Sequence = IIf(IsDBNull(oRow.Item("SEQUENCE")), String.Empty, oRow.Item("SEQUENCE")),
.Value = oRow.ItemEx(Of String)("VALUE") .Value = IIf(IsDBNull(oRow.Item("VALUE")), String.Empty, oRow.Item("VALUE"))
} }
oIndexes.Add(oAutomaticIndex) oIndexes.Add(oAutomaticIndex)
@@ -125,15 +125,15 @@ Namespace Methods.GlobalIndexer
For Each oRow As DataRow In oManualIndexes.Table.Rows For Each oRow As DataRow In oManualIndexes.Table.Rows
Dim oManualIndex As New ManualIndex With { Dim oManualIndex As New ManualIndex With {
.Id = oRow.ItemEx(Of Integer)("GUID"), .Id = oRow.Item("GUID"),
.Name = oRow.ItemEx(Of String)("INDEXNAME"), .Name = oRow.Item("INDEXNAME"),
.ProfileId = oRow.ItemEx(Of Integer)("DOK_ID"), .ProfileId = oRow.Item("DOK_ID"),
.IsOptional = oRow.ItemEx(Of Boolean)("OPTIONAL"), .IsOptional = oRow.Item("OPTIONAL"),
.IsMultiselect = oRow.ItemEx(Of String)("MULTISELECT"), .IsMultiselect = oRow.Item("MULTISELECT"),
.SQLCommand = oRow.ItemEx(Of String)("SQL_RESULT"), .SQLCommand = oRow.Item("SQL_RESULT"),
.SQLConnectionId = oRow.ItemEx(Of Integer)("CONNECTION_ID"), .SQLConnectionId = oRow.Item("CONNECTION_ID"),
.DefaultValue = oRow.ItemEx(Of String)("DEFAULT_VALUE"), .DefaultValue = oRow.Item("DEFAULT_VALUE"),
.DataType = oRow.ItemEx(Of String)("DATATYPE") .DataType = oRow.Item("DATATYPE")
} }
oIndexes.Add(oManualIndex) oIndexes.Add(oManualIndex)
@@ -179,16 +179,16 @@ Namespace Methods.GlobalIndexer
For Each oRow As DataRow In oPostProcessingSteps.Table.Rows For Each oRow As DataRow In oPostProcessingSteps.Table.Rows
Dim oStep As New PostProcessingStep With { Dim oStep As New PostProcessingStep With {
.Id = oRow.ItemEx(Of Integer)("GUID"), .Id = oRow.Item("GUID"),
.IndexId = oRow.ItemEx(Of Integer)("IDXMAN_ID"), .IndexId = oRow.Item("IDXMAN_ID"),
.[Variant] = oRow.ItemEx(Of String)("VARIANT"), .[Variant] = oRow.Item("VARIANT"),
.Type = oRow.ItemEx(Of String)("TYPE"), .Type = oRow.Item("TYPE"),
.Function1 = oRow.ItemEx(Of String)("FUNCTION1"), .Function1 = oRow.Item("FUNCTION1"),
.Function2 = oRow.ItemEx(Of String)("FUNCTION2"), .Function2 = oRow.Item("FUNCTION2"),
.Text1 = oRow.ItemEx(Of String)("Text1"), .Text1 = oRow.Item("Text1"),
.Text2 = oRow.ItemEx(Of String)("Text2"), .Text2 = oRow.Item("Text2"),
.Text3 = oRow.ItemEx(Of String)("Text3"), .Text3 = oRow.Item("Text3"),
.Sequence = oRow.ItemEx(Of Integer)("SEQUENCE") .Sequence = oRow.Item("SEQUENCE")
} }
oSteps.Add(oStep) oSteps.Add(oStep)

View File

@@ -25,12 +25,12 @@ Namespace Methods.IDB.GetFileObject
LogAndThrow("Error while getting FileObject data!") LogAndThrow("Error while getting FileObject data!")
End If End If
Dim oRow As DataRow = oTable.First() Dim oRow As DataRow = oTable.Rows(0)
Dim oFileHash As String = oRow.ItemEx("FILE_HASH", "") Dim oFileHash As String = oRow.Item("FILE_HASH")
Dim oFileSize As Long = oRow.ItemEx(Of Long)("FILE_SIZE", 0) Dim oFileSize As Long = oRow.Item("FILE_SIZE")
Dim oFileExtension As String = oRow.ItemEx(Of String)("EXTENSION") Dim oFileExtension As String = oRow.Item("EXTENSION")
Dim oFilePath = oRow.ItemEx("RELPATH", "") Dim oFilePath = oRow.Item("RELPATH")
Dim oFileName = oRow.ItemEx("Filename", "") Dim oFileName = oRow.Item("Filename")
Dim oFullFileName = Path.Combine(oFilePath, oFileName) Dim oFullFileName = Path.Combine(oFilePath, oFileName)
Dim oFileObject As New FileObject With { Dim oFileObject As New FileObject With {

View File

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

View File

@@ -29,17 +29,17 @@ Public Class DatatableJob
Try Try
Dim oMSSQL As MSSQLServer = oJobData.Item("MSSQL") Dim oMSSQL As MSSQLServer = oJobData.Item("MSSQL")
Dim oCronSQL As String = $"SELECT * FROM TBAPPSERV_CRON_DETAIL WHERE CRON_ID = {oCronJobId}" Dim oCronSQL As String = $"SELECT * FROM TBAPPSERV_CRON_DETAIL WITH (NOLOCK) WHERE CRON_ID = {oCronJobId}"
Dim oCronDetails As DataTable = oMSSQL.GetDatatable(oCronSQL) Dim oCronDetails As DataTable = oMSSQL.GetDatatable(oCronSQL)
For Each oRow As DataRow In oCronDetails.Rows For Each oRow As DataRow In oCronDetails.Rows
Dim oDatatableName As String = NotNull(oRow.Item("DT_NAME"), String.Empty) Dim oDatatableName As String = IIf(IsDBNull(oRow.Item("DT_NAME")), String.Empty, oRow.Item("DT_NAME"))
Dim oParentColumn As String = NotNull(oRow.Item("DT_COLUMN"), String.Empty) Dim oParentColumn As String = IIf(IsDBNull(oRow.Item("DT_COLUMN")), String.Empty, oRow.Item("DT_COLUMN"))
Dim oChildColumn As String = NotNull(oRow.Item("CHILD_DT_COLUMN"), String.Empty) Dim oChildColumn As String = IIf(IsDBNull(oRow.Item("CHILD_DT_COLUMN")), String.Empty, oRow.Item("CHILD_DT_COLUMN"))
Dim oConnectionId As Integer = NotNull(oRow.Item("CON_ID"), String.Empty) Dim oConnectionId As Integer = IIf(IsDBNull(oRow.Item("CON_ID")), 0, oRow.Item("CON_ID"))
Dim oTitle As String = NotNull(oRow.Item("TITLE"), String.Empty) Dim oTitle As String = IIf(IsDBNull(oRow.Item("TITLE")), String.Empty, oRow.Item("TITLE"))
Dim oSQL As String = NotNull(oRow.Item("COMMAND"), String.Empty) Dim oSQL As String = IIf(IsDBNull(oRow.Item("COMMAND")), String.Empty, oRow.Item("COMMAND"))
Dim oIndexColumns As String = NotNull(oRow.Item("INDEX_COLUMNS"), String.Empty) Dim oIndexColumns As String = IIf(IsDBNull(oRow.Item("INDEX_COLUMNS")), String.Empty, oRow.Item("INDEX_COLUMNS"))
Try Try
oLogger.Debug("Running Command-Job [{0}]", oTitle) oLogger.Debug("Running Command-Job [{0}]", oTitle)
@@ -80,7 +80,7 @@ Public Class DatatableJob
.DetailRow = oRow .DetailRow = oRow
} }
Dim oChildTableNAme As String = NotNull(oRow.Item("CHILD_DT_NAME"), String.Empty) Dim oChildTableNAme As String = IIf(IsDBNull(oRow.Item("CHILD_DT_NAME")), String.Empty, oRow.Item("CHILD_DT_NAME"))
If oChildTableNAme <> String.Empty Then If oChildTableNAme <> String.Empty Then
oLogger.Debug("Child Datatable [{0}] defined, Relation: Parent [{1}] -> Child [{2}]", oChildTableNAme, oParentColumn, oChildColumn) oLogger.Debug("Child Datatable [{0}] defined, Relation: Parent [{1}] -> Child [{2}]", oChildTableNAme, oParentColumn, oChildColumn)

View File

@@ -11,7 +11,10 @@ Public Class JobListener
Inherits JobListenerSupport Inherits JobListenerSupport
Public Overrides ReadOnly Property Name As String = "JobListener" Public Overrides ReadOnly Property Name As String = "JobListener"
Public Property Dataset As DataSet
' ✅ Verwaltung mit ReaderWriterLockSlim statt Shadow-Copy
Private ReadOnly _Dataset As DataSet
Private Shared ReadOnly _DatasetLock As New ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion)
Private ReadOnly _Logger As Logger Private ReadOnly _Logger As Logger
Private ReadOnly _LogConfig As LogConfig Private ReadOnly _LogConfig As LogConfig
@@ -23,9 +26,44 @@ Public Class JobListener
_LogConfig = LogConfig _LogConfig = LogConfig
_Logger = LogConfig.GetLogger() _Logger = LogConfig.GetLogger()
_MSSQL = MSSQL _MSSQL = MSSQL
Dataset = ResultDataSet _Dataset = ResultDataSet
_Logger.Debug("JobListener initialized with ReaderWriterLockSlim for thread-safe access")
End Sub End Sub
' ✅ Thread-sichere Methode zum Abrufen einer Tabelle
Public Function GetTableSafely(tableName As String) As DataTable
Try
_DatasetLock.EnterReadLock()
If _Dataset.Tables.Contains(tableName) Then
' Kopie nur von der einzelnen Tabelle, nicht vom ganzen Dataset!
Return _Dataset.Tables(tableName).Copy()
Else
Return Nothing
End If
Finally
_DatasetLock.ExitReadLock()
End Try
End Function
' ✅ Thread-sichere Methode zum Prüfen ob Tabelle existiert
Public Function TableExists(tableName As String) As Boolean
Try
_DatasetLock.EnterReadLock()
Return _Dataset.Tables.Contains(tableName)
Finally
_DatasetLock.ExitReadLock()
End Try
End Function
' ✅ Thread-sicherer Zugriff auf Dataset (nur für GetCachedTables)
Public Function GetCurrentDataset() As DataSet
' Keine Kopie - nur für Metadaten-Zugriff (Tabellennamen)
Return _Dataset
End Function
Public Overrides Function JobWasExecuted(context As IJobExecutionContext, jobException As JobExecutionException, Optional cancellationToken As CancellationToken = Nothing) As Task Public Overrides Function JobWasExecuted(context As IJobExecutionContext, jobException As JobExecutionException, Optional cancellationToken As CancellationToken = Nothing) As Task
_Logger.Info("Job [{0}] was executed successfully. Saving Data.", context.JobDetail.Key) _Logger.Info("Job [{0}] was executed successfully. Saving Data.", context.JobDetail.Key)
@@ -33,10 +71,11 @@ Public Class JobListener
For Each oTableResult As JobResult.ResultTable In oResult.Tables For Each oTableResult As JobResult.ResultTable In oResult.Tables
Try Try
_Logger.Debug("Saving Datatable [{0}]", oTableResult.Table) _Logger.Debug("Saving Datatable [{0}]", oTableResult.Table.TableName)
SaveDataTables(oTableResult) SaveDataTables(oTableResult)
Catch ex As Exception Catch ex As Exception
_Logger.Error(ex)
_Logger.Error("Error while executing SaveDataTables for {0}", oTableResult.Table.TableName) _Logger.Error("Error while executing SaveDataTables for {0}", oTableResult.Table.TableName)
End Try End Try
Next Next
@@ -44,6 +83,86 @@ Public Class JobListener
Return MyBase.JobWasExecuted(context, jobException, cancellationToken) Return MyBase.JobWasExecuted(context, jobException, cancellationToken)
End Function End Function
' ✅ OPTIMIERT: SaveDataTables mit direktem Write-Lock
Public Sub SaveDataTables(Result As JobResult.ResultTable)
Dim oStopWatch As New Stopwatch()
Try
Dim oTable As DataTable = Result.Table
Dim oName As String = Result.DetailRow.Item("DT_NAME")
Dim oDetailId As Integer = Result.DetailRow.Item("GUID")
_Logger.Debug("Starting thread-safe update for table [{0}]", oName)
' ✅ SCHRITT 1: Write-Lock anfordern (blockiert Leser während Update)
oStopWatch.Start()
_DatasetLock.EnterWriteLock()
_Logger.Debug("[Lock] Write-Lock acquired for table [{0}]", oName)
Try
' ✅ SCHRITT 2: Direkte Änderungen im Dataset
If _Dataset.Tables.Contains(oName) Then
_Logger.Debug("Datatable [{0}] already exists, replacing.", oName)
If Result.ChildTable IsNot Nothing Then
ReplaceExistingTable(oName, oTable, _Dataset, Result.ChildTable)
AddRelation(oName, Result.TableRelationColumn, Result.ChildTable.TableName, Result.ChildRelationColumn, _Dataset)
Else
ReplaceExistingTable(oName, oTable, _Dataset)
End If
Else
_Logger.Debug("Datatable [{0}] does not exist yet, adding.", oName)
AddNewTable(oName, oTable, _Dataset)
If Result.ChildTable IsNot Nothing Then
AddNewTable(Result.ChildTable.TableName, Result.ChildTable, _Dataset)
AddRelation(oName, Result.TableRelationColumn, Result.ChildTable.TableName, Result.ChildRelationColumn, _Dataset)
End If
End If
_Logger.Info("Dataset successfully updated with table [{0}]", oName)
Finally
' ✅ SCHRITT 3: Write-Lock freigeben (so schnell wie möglich!)
_DatasetLock.ExitWriteLock()
oStopWatch.Stop()
' ✅ Performance-Warning bei langsamen Updates
If oStopWatch.ElapsedMilliseconds > 500 Then
_Logger.Warn("[Performance] Table update took {0}ms (> 500ms threshold)", oStopWatch.ElapsedMilliseconds)
Else
_Logger.Debug("[Performance] Table update completed in {0}ms", oStopWatch.ElapsedMilliseconds)
End If
End Try
' ✅ SCHRITT 4: Speichern in Historie (außerhalb des Locks)
Dim oMemoryUsage = GC.GetTotalMemory(True)
_Logger.Debug("Estimated memory usage after Job is [{0}]", FormatBytes(oMemoryUsage))
_MSSQL.ExecuteNonQuery($"INSERT INTO TBAPPSERV_CRON_DETAIL_HISTORY (DETAIL_ID) VALUES ({oDetailId})")
Catch ex As Exception
_Logger.Warn("Unexpected error in SaveDataTables: {0}", ex.Message)
_Logger.Error(ex)
End Try
End Sub
Private Shared Function FormatBytes(bytes As Long) As String
Const KB As Long = 1024
Const MB As Long = KB * 1024
Const GB As Long = MB * 1024
Select Case bytes
Case >= GB
Return $"{bytes / GB:N2} GB"
Case >= MB
Return $"{bytes / MB:N2} MB"
Case >= KB
Return $"{bytes / KB:N2} KB"
Case Else
Return $"{bytes} Bytes"
End Select
End Function
Public Sub ReplaceExistingTable(Name As String, Table As DataTable, DataSet As DataSet, Optional ChildTable As DataTable = Nothing) Public Sub ReplaceExistingTable(Name As String, Table As DataTable, DataSet As DataSet, Optional ChildTable As DataTable = Nothing)
Try Try
Dim oDatatableNameTemp As String = Name & "-TEMP" Dim oDatatableNameTemp As String = Name & "-TEMP"
@@ -103,13 +222,12 @@ Public Class JobListener
DataSet.Tables.Item(oDatatableNameTemp).TableName = Name DataSet.Tables.Item(oDatatableNameTemp).TableName = Name
Catch ex As Exception Catch ex As Exception
_Logger.Error(ex) _Logger.Error(ex)
Throw ex Throw
End Try End Try
End Sub End Sub
Public Sub AddNewTable(Name As String, Table As DataTable, DataSet As DataSet) Public Sub AddNewTable(Name As String, Table As DataTable, DataSet As DataSet)
_Logger.Debug("DataTable [{0}] does not exist, adding to DataSet", Name) _Logger.Debug("DataTable [{0}] does not exist, adding to DataSet", Name)
DataSet.Tables.Add(Table) DataSet.Tables.Add(Table)
End Sub End Sub
@@ -117,9 +235,9 @@ Public Class JobListener
Return $"{ParentTableName}-{ChildTableName}" Return $"{ParentTableName}-{ChildTableName}"
End Function End Function
Public Sub AddRelation(ParentTableName As String, ParentColumnName As String, ChildTableName As String, ChildColumnName As String) Public Sub AddRelation(ParentTableName As String, ParentColumnName As String, ChildTableName As String, ChildColumnName As String, TargetDataSet As DataSet)
Dim oChild As DataTable = Dataset.Tables.Item(ChildTableName) Dim oChild As DataTable = TargetDataSet.Tables.Item(ChildTableName)
Dim oParent As DataTable = Dataset.Tables.Item(ParentTableName) Dim oParent As DataTable = TargetDataSet.Tables.Item(ParentTableName)
Dim oRelationName As String = GetRelationName(ParentTableName, ChildTableName) Dim oRelationName As String = GetRelationName(ParentTableName, ChildTableName)
Dim oParentColumn As DataColumn = oParent.Columns.Item(ParentColumnName) Dim oParentColumn As DataColumn = oParent.Columns.Item(ParentColumnName)
@@ -128,12 +246,13 @@ Public Class JobListener
_Logger.Debug("New Relation: {0}/{1} => {2}/{3}", ParentTableName, ParentColumnName, ChildTableName, ChildColumnName) _Logger.Debug("New Relation: {0}/{1} => {2}/{3}", ParentTableName, ParentColumnName, ChildTableName, ChildColumnName)
Try Try
_Logger.Debug("Creating Relation [{0}]", oRelationName) _Logger.Debug("Creating Relation [{0}]", oRelationName)
_Logger.Debug("ParentColumn exists: {0}", IsNothing(oParentColumn)) _Logger.Debug("ParentColumn exists: {0}", Not IsNothing(oParentColumn))
_Logger.Debug("ChildColumn exists: {0}", IsNothing(oChildColumn)) _Logger.Debug("ChildColumn exists: {0}", Not IsNothing(oChildColumn))
Dim oRelation As New DataRelation(oRelationName, oParentColumn, oChildColumn) Dim oRelation As New DataRelation(oRelationName, oParentColumn, oChildColumn)
_Logger.Debug("Adding Relation [{0}]", oRelationName) _Logger.Debug("Adding Relation [{0}]", oRelationName)
Dataset.Relations.Add(oRelation) TargetDataSet.Relations.Add(oRelation)
Catch ex As ArgumentNullException Catch ex As ArgumentNullException
_Logger.Error(ex) _Logger.Error(ex)
@@ -145,7 +264,7 @@ Public Class JobListener
Catch ex As InvalidConstraintException Catch ex As InvalidConstraintException
_Logger.Error(ex) _Logger.Error(ex)
_Logger.Warn("DuplicateNameException in AddRelation: {0}", ex.Message) _Logger.Warn("InvalidConstraintException in AddRelation: {0}", ex.Message)
Catch ex As ArgumentException Catch ex As ArgumentException
_Logger.Error(ex) _Logger.Error(ex)
@@ -158,55 +277,6 @@ Public Class JobListener
End Try End Try
End Sub End Sub
Public Sub SaveDataTables(Result As JobResult.ResultTable)
Try
Dim oTable As DataTable = Result.Table
Dim oName As String = Result.DetailRow.Item("DT_NAME")
Dim oDetailId As Integer = Result.DetailRow.Item("GUID")
' Used for debugging relations and constraints
'_Logger.Debug("Dataset BEFORE saving datatables")
'ListTables(Dataset)
If Dataset.Tables.Contains(oName) Then
_Logger.Debug("Datatable [{0}] already exists, replacing.", oName)
' Replace existing table
If Result.ChildTable IsNot Nothing Then
ReplaceExistingTable(oName, oTable, Dataset, Result.ChildTable)
AddRelation(oName, Result.TableRelationColumn, Result.ChildTable.TableName, Result.ChildRelationColumn)
Else
ReplaceExistingTable(oName, oTable, Dataset)
End If
Else
_Logger.Debug("Datatable [{0}] does not exist yet, adding.", oName)
AddNewTable(oName, oTable, Dataset)
If Result.ChildTable IsNot Nothing Then
AddNewTable(Result.ChildTable.TableName, Result.ChildTable, Dataset)
AddRelation(oName, Result.TableRelationColumn, Result.ChildTable.TableName, Result.ChildRelationColumn)
End If
End If
' Used for debugging relations and constraints
'_Logger.Debug("Dataset AFTER saving datatables")
'ListTables(Dataset)
Dim oMemoryUsage = GC.GetTotalMemory(True)
Dim oUsageString = Utils.BytesToString(oMemoryUsage)
_Logger.Debug("Estimated memory usage after Job is [{0}]", oUsageString)
_MSSQL.ExecuteNonQuery($"INSERT INTO TBAPPSERV_CRON_DETAIL_HISTORY (DETAIL_ID) VALUES ({oDetailId})")
Catch ex As Exception
_Logger.Warn("Unexpected error in SaveDataTables: {0}", ex.Message)
_Logger.Error(ex)
End Try
End Sub
Private Sub ListTables(dataset As DataSet) Private Sub ListTables(dataset As DataSet)
Dim oIndex As Integer = 1 Dim oIndex As Integer = 1
@@ -226,4 +296,10 @@ Public Class JobListener
oIndex += 1 oIndex += 1
Next Next
End Sub End Sub
End Class
' ✅ Cleanup beim Dispose
Protected Overrides Sub Finalize()
_DatasetLock?.Dispose()
MyBase.Finalize()
End Sub
End Class

View File

@@ -13,20 +13,25 @@ Public Class Scheduler
Private ReadOnly _MSSQL As MSSQLServer Private ReadOnly _MSSQL As MSSQLServer
Private _Scheduler As IScheduler Private _Scheduler As IScheduler
Private ReadOnly _JobListener As JobListener Private ReadOnly _JobListener As JobListener
Private ReadOnly _GlobalState As GlobalState ' ✅ NEU
Private ReadOnly _Props = New NameValueCollection From { Private ReadOnly _Props = New NameValueCollection From {
{"quartz.serializer.type", "binary"}, {"quartz.serializer.type", "binary"},
{"quartz.threadPool.maxConcurrency", 1} {"quartz.threadPool.maxConcurrency", 3}
} }
Private Const JOB_GROUP As String = "DatatableJobs" Private Const JOB_GROUP As String = "DatatableJobs"
Public Sub New(pLogConfig As LogConfig, pMSSQL_Config As MSSQLServer, pTableStore As DataSet) Public Sub New(pLogConfig As LogConfig, pMSSQL_Config As MSSQLServer, pTableStore As DataSet, pGlobalState As GlobalState)
MyBase.New(pLogConfig) MyBase.New(pLogConfig)
_Factory = New StdSchedulerFactory(_Props) _Factory = New StdSchedulerFactory(_Props)
_MSSQL = pMSSQL_Config _MSSQL = pMSSQL_Config
_JobListener = New JobListener(pLogConfig, _MSSQL, pTableStore) _JobListener = New JobListener(pLogConfig, _MSSQL, pTableStore)
_GlobalState = pGlobalState
_GlobalState.JobListener = _JobListener
Logger.Debug("JobListener registered in GlobalState")
Logging.LogProvider.SetCurrentLogProvider(New LogProvider(Logger)) Logging.LogProvider.SetCurrentLogProvider(New LogProvider(Logger))
End Sub End Sub
@@ -108,7 +113,7 @@ Public Class Scheduler
End Sub End Sub
Public Async Function GetCronJobs() As Task(Of DataTable) Public Async Function GetCronJobs() As Task(Of DataTable)
Try Try
Dim oSQL As String = "SELECT * FROM TBAPPSERV_CRON_JOB WHERE ACTIVE = 1" Dim oSQL As String = "SELECT * FROM TBAPPSERV_CRON_JOB WITH (NOLOCK) WHERE ACTIVE = 1"
Dim oDatatable As DataTable = Await _MSSQL.GetDatatableAsync(oSQL) Dim oDatatable As DataTable = Await _MSSQL.GetDatatableAsync(oSQL)
Return oDatatable Return oDatatable
@@ -119,7 +124,7 @@ Public Class Scheduler
Public Async Function GetCronJobDetails(CronJobId As Integer) As Task(Of DataTable) Public Async Function GetCronJobDetails(CronJobId As Integer) As Task(Of DataTable)
Try Try
Dim oSQL As String = $"SELECT * FROM TBAPPSERV_CRON_DETAIL WHERE CRON_ID = {CronJobId}" Dim oSQL As String = $"SELECT * FROM TBAPPSERV_CRON_DETAIL WITH (NOLOCK) WHERE CRON_ID = {CronJobId}"
Dim oDatatable As DataTable = Await _MSSQL.GetDatatableAsync(oSQL) Dim oDatatable As DataTable = Await _MSSQL.GetDatatableAsync(oSQL)
Return oDatatable Return oDatatable

View File

@@ -77,7 +77,7 @@ Public Class WindowsService
GlobalState = New GlobalState(LogConfig, MSSQL_IDB, MSSQL_ECM) GlobalState = New GlobalState(LogConfig, MSSQL_IDB, MSSQL_ECM)
Dim oMSSQLServer = GetMSSQL_Config(LogConfigScheduler) Dim oMSSQLServer = GetMSSQL_Config(LogConfigScheduler)
Scheduler = New Scheduler(LogConfigScheduler, oMSSQLServer, GlobalState.TableStore) Scheduler = New Scheduler(LogConfigScheduler, oMSSQLServer, GlobalState.TableStore, GlobalState)
Logger.Info("Loading Global Data") Logger.Info("Loading Global Data")
GlobalState.LoadObjectStores() GlobalState.LoadObjectStores()
@@ -94,7 +94,6 @@ Public Class WindowsService
EDMIService.Firebird = Firebird EDMIService.Firebird = Firebird
EDMIService.LogConfig = LogConfig EDMIService.LogConfig = LogConfig
EDMIService.AppConfig = Config EDMIService.AppConfig = Config
EDMIService.Filesystem = Filesystem
EDMIService.GlobalState = GlobalState EDMIService.GlobalState = GlobalState
EDMIService.Scheduler = Scheduler EDMIService.Scheduler = Scheduler
@@ -187,8 +186,13 @@ Public Class WindowsService
Private Function GetMSSQL_Config(pLogConfig As LogConfig) As MSSQLServer Private Function GetMSSQL_Config(pLogConfig As LogConfig) As MSSQLServer
Logger.Debug("Connecting to Config MSSQL") Logger.Debug("Connecting to Config MSSQL")
If Config.ConnectionString_Config = String.Empty Then If Config.ConnectionString_Config = String.Empty Then
Logger.Warn("Configuration for ConnectionString_Config is missing.") If Config.ConnectionString_ECM <> String.Empty Then
Throw New ArgumentNullException("ConnectionString_Config") Logger.Info("Using ConnectionString_ECM for Config Database connection.")
Return GetMSSQL_ECM(pLogConfig)
Else
Logger.Warn("Configuration for ConnectionString_Config is missing and ConnectionString_ECM is also missing.")
Throw New ArgumentNullException("ConnectionString_Config")
End If
End If End If
Dim oMSSQL = New MSSQLServer(pLogConfig, Config.ConnectionString_Config) Dim oMSSQL = New MSSQLServer(pLogConfig, Config.ConnectionString_Config)

View File

@@ -2,7 +2,6 @@
<packages> <packages>
<package id="FirebirdSql.Data.FirebirdClient" version="7.5.0" targetFramework="net472" /> <package id="FirebirdSql.Data.FirebirdClient" version="7.5.0" targetFramework="net472" />
<package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net472" /> <package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net472" />
<package id="NLog" version="5.0.5" targetFramework="net472" />
<package id="Quartz" version="3.5.0" targetFramework="net462" /> <package id="Quartz" version="3.5.0" targetFramework="net462" />
<package id="System.Buffers" version="4.5.1" targetFramework="net472" /> <package id="System.Buffers" version="4.5.1" targetFramework="net472" />
<package id="System.Diagnostics.DiagnosticSource" version="4.7.1" targetFramework="net472" /> <package id="System.Diagnostics.DiagnosticSource" version="4.7.1" targetFramework="net472" />