Verbesserung von Stabilität und Fehlerbehandlung
- Implementierung von `IDisposable` in der Klasse `Client`, um Ressourcen wie Timer und Kanäle ordnungsgemäß freizugeben. - Einführung von `ActiveClients` und `ClientStatus` zur Verfolgung und Statusanzeige aktiver Clients. - Verbesserte Fehlerbehandlung mit der Methode `HandleCommunicationError`, die Kommunikationsfehler protokolliert, den Client offline setzt und einen Reconnect auslöst. - Optimierung der Reconnect-Logik mit asynchronen Wiederverbindungsversuchen und gestaffelten Verzögerungen. - Erweiterung der Konstruktoren in `Client` um einen optionalen `pClientName`-Parameter und Generierung eines eindeutigen `ClientId`. - Verbesserte Timer-Logik und asynchrone Verarbeitung in `UpdateTimer_Elapsed`. - Einführung der Methode `EnsureAvailable`, um sicherzustellen, dass der Kanal vor Service-Aufrufen verfügbar ist. - Hinzufügen asynchroner Varianten für Service-Methoden (`GetDatatable`, `GetScalarValue`, `ExecuteNonQuery`) und Fallback auf direkte Datenbankzugriffe. - Verbesserte Timeout-Einstellungen und Verbindungsverwaltung in der Klasse `Channel`. - Erweiterungen in `DatabaseWithFallback` für asynchrone Methoden und detaillierteres Logging. - Aktualisierung der Assembly-Version auf `2.7.0`.
This commit is contained in:
@@ -7,6 +7,7 @@ Imports DigitalData.Modules.EDMI.API.Rights
|
||||
Imports DigitalData.Modules.Logging
|
||||
|
||||
Public Class Client
|
||||
Implements IDisposable
|
||||
' Constants
|
||||
Private Const UPDATE_INTERVAL_IN_MINUTES As Integer = 1
|
||||
|
||||
@@ -23,9 +24,53 @@ Public Class Client
|
||||
Private _CachedTables As New List(Of String)
|
||||
Private _IsOnline As Boolean
|
||||
Private _Channel As IEDMIServiceChannel
|
||||
|
||||
Private _ClientName As String
|
||||
' Static Registry
|
||||
Private Shared ReadOnly _ActiveClients As New Collections.Concurrent.ConcurrentDictionary(Of String, ClientStatus)
|
||||
Private ReadOnly _ClientId As String ' ← Neu: eindeutiger interner Key
|
||||
Public Shared ReadOnly Property ActiveClients As IReadOnlyDictionary(Of String, ClientStatus)
|
||||
Get
|
||||
Return _ActiveClients
|
||||
End Get
|
||||
End Property
|
||||
''' <summary>
|
||||
''' Returns a snapshot of all currently registered client instances
|
||||
''' </summary>
|
||||
Public Shared Function GetAllClientStatus() As List(Of ClientStatus)
|
||||
Return _ActiveClients.Values.ToList()
|
||||
End Function
|
||||
' Update Timer
|
||||
Private WithEvents UpdateTimer As New Timers.Timer
|
||||
Private _Disposed As Boolean = False
|
||||
|
||||
''' <summary>
|
||||
''' Closes the channel and releases all resources
|
||||
''' </summary>
|
||||
Public Sub Dispose() Implements IDisposable.Dispose
|
||||
Dispose(True)
|
||||
GC.SuppressFinalize(Me)
|
||||
End Sub
|
||||
Protected Overridable Sub Dispose(disposing As Boolean)
|
||||
If _Disposed Then Return
|
||||
|
||||
If disposing Then
|
||||
UpdateTimer.Stop()
|
||||
UpdateTimer.Dispose()
|
||||
|
||||
If _Channel IsNot Nothing Then
|
||||
Channel.CloseChannel(_Channel)
|
||||
_Channel = Nothing
|
||||
End If
|
||||
|
||||
' Aus Registry austragen
|
||||
Dim oRemoved As ClientStatus = Nothing
|
||||
_ActiveClients.TryRemove(_ClientId, oRemoved)
|
||||
Logger.Debug("Client [{0}] unregistered. Total active clients: [{1}]", _ClientName, _ActiveClients.Count)
|
||||
Logger.Debug("Client disposed. Channel closed.")
|
||||
End If
|
||||
|
||||
_Disposed = True
|
||||
End Sub
|
||||
|
||||
' Public Variables
|
||||
Public ReadOnly Property CachedTables
|
||||
@@ -72,9 +117,12 @@ Public Class Client
|
||||
''' </summary>
|
||||
''' <param name="pLogConfig">LogConfig object</param>
|
||||
''' <param name="pServiceAdress">The IP address/hostname and port, separated by semicolon or colon, ex. 1.2.3.4:9000</param>
|
||||
Public Sub New(pLogConfig As LogConfig, pServiceAdress As String)
|
||||
''' <param name="pClientName">Optional identifier for this client instance (e.g. application name or hostname)</param>
|
||||
Public Sub New(pLogConfig As LogConfig, pServiceAdress As String, Optional pClientName As String = "")
|
||||
LogConfig = pLogConfig
|
||||
Logger = pLogConfig.GetLogger()
|
||||
_ClientName = If(String.IsNullOrWhiteSpace(pClientName), Environment.MachineName, pClientName)
|
||||
_ClientId = $"{_ClientName}_{Guid.NewGuid().ToString("N").Substring(0, 8)}" ' ← eindeutig
|
||||
|
||||
UpdateTimer.Interval = 60 * 1000 * UPDATE_INTERVAL_IN_MINUTES
|
||||
UpdateTimer.Start()
|
||||
@@ -85,8 +133,8 @@ Public Class Client
|
||||
ChannelManager = New Channel(pLogConfig, _ServerAddress)
|
||||
AddHandler ChannelManager.Reconnect, AddressOf Reconnect
|
||||
|
||||
Logger.Debug("Ready for connection to Service at: [{0}:{1}]", _ServerAddress.Host, _ServerAddress.Port)
|
||||
|
||||
Logger.Debug("Ready for connection to Service at: [{0}:{1}] | ClientName=[{2}] | ClientId=[{3}]",
|
||||
_ServerAddress.Host, _ServerAddress.Port, _ClientName, _ClientId)
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
End Try
|
||||
@@ -98,9 +146,12 @@ Public Class Client
|
||||
''' <param name="pLogConfig">LogConfig object</param>
|
||||
''' <param name="pIPAddress">The IP address to connect to</param>
|
||||
''' <param name="pPortNumber">The Port number to use for the connection</param>
|
||||
Public Sub New(pLogConfig As LogConfig, pIPAddress As String, pPortNumber As Integer)
|
||||
''' <param name="pClientName">Optional identifier for this client instance (e.g. application name or hostname)</param>
|
||||
Public Sub New(pLogConfig As LogConfig, pIPAddress As String, pPortNumber As Integer, Optional pClientName As String = "")
|
||||
LogConfig = pLogConfig
|
||||
Logger = pLogConfig.GetLogger()
|
||||
_ClientName = If(String.IsNullOrWhiteSpace(pClientName), Environment.MachineName, pClientName)
|
||||
_ClientId = $"{_ClientName}_{Guid.NewGuid().ToString("N").Substring(0, 8)}" ' ← eindeutig
|
||||
|
||||
UpdateTimer.Interval = 60 * 1000 * UPDATE_INTERVAL_IN_MINUTES
|
||||
UpdateTimer.Start()
|
||||
@@ -111,13 +162,12 @@ Public Class Client
|
||||
ChannelManager = New Channel(pLogConfig, _ServerAddress)
|
||||
AddHandler ChannelManager.Reconnect, AddressOf Reconnect
|
||||
|
||||
Logger.Debug("Ready for connection to Service at: [{0}:{1}]", _ServerAddress.Host, _ServerAddress.Port)
|
||||
|
||||
Logger.Debug("Ready for connection to Service at: [{0}:{1}] | ClientName=[{2}] | ClientId=[{3}]",
|
||||
_ServerAddress.Host, _ServerAddress.Port, _ClientName, _ClientId)
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Connect to the service
|
||||
''' </summary>
|
||||
@@ -133,13 +183,26 @@ Public Class Client
|
||||
If oResponse.OK Then
|
||||
_ClientConfig = oResponse.ClientConfig
|
||||
Else
|
||||
Logger.Warn("Client Configuration could not be loaded: [{0}]", oResponse.ErrorMessage)
|
||||
Logger.Warn("⚠Client Configuration could not be loaded: [{0}]", oResponse.ErrorMessage)
|
||||
End If
|
||||
|
||||
Logger.Info($"Connection to AppService [{ServerAddress}] successfully established!")
|
||||
|
||||
Logger.Info("✔✔Connection to AppService [{0}] successfully established! | Client=[{1}] | Id=[{2}]",
|
||||
ServerAddress, _ClientName, _ClientId)
|
||||
_IsOnline = True
|
||||
|
||||
' CachedTables sofort befüllen – nicht auf den ersten Timer-Tick warten
|
||||
Try
|
||||
Dim oTables As String() = _Channel.GetCachedTables()
|
||||
_CachedTables = oTables.Select(Function(t) t.ToUpper).ToList()
|
||||
Logger.Debug("✔ CachedTables loaded on connect: [{0}]", _CachedTables.Count)
|
||||
Catch ex As Exception
|
||||
Logger.Warn("⚠ CachedTables could not be loaded on connect: {0}", ex.Message)
|
||||
_CachedTables = New List(Of String)
|
||||
End Try
|
||||
' In Registry eintragen
|
||||
_ActiveClients(_ClientId) = GetStatus()
|
||||
Logger.Info("Client [{0}] registered with Id=[{1}]. Total active clients: [{2}]", _ClientName, _ClientId, _ActiveClients.Count)
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
_IsOnline = False
|
||||
@@ -152,32 +215,83 @@ Public Class Client
|
||||
''' <summary>
|
||||
''' Aborts the channel and creates a new connection
|
||||
''' </summary>
|
||||
Public Sub Reconnect()
|
||||
Logger.Warn("Connection faulted. Trying to reconnect..")
|
||||
Public Async Sub Reconnect()
|
||||
Logger.Warn("⚠ Connection faulted. Trying to reconnect..")
|
||||
|
||||
Try
|
||||
_Channel.Abort()
|
||||
_Channel = ChannelManager.GetChannel()
|
||||
_Channel.Open()
|
||||
Dim oRetryDelays = {2, 5, 15, 30}
|
||||
|
||||
_IsOnline = True
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
End Try
|
||||
For Each oDelay In oRetryDelays
|
||||
Try
|
||||
Await Task.Delay(TimeSpan.FromSeconds(oDelay))
|
||||
Logger.Debug($"Reconnect attempt after {oDelay}s delay...")
|
||||
|
||||
Channel.CloseChannel(_Channel) ' Sauber schließen statt Abort
|
||||
_Channel = ChannelManager.GetChannel()
|
||||
_Channel.Open()
|
||||
|
||||
_IsOnline = True
|
||||
Logger.Info("Reconnect successful.")
|
||||
Return
|
||||
Catch ex As Exception
|
||||
Logger.Warn($"⚠ Reconnect failed: {ex.Message}")
|
||||
_IsOnline = False
|
||||
End Try
|
||||
Next
|
||||
|
||||
Logger.Error("All reconnect attempts failed. Service unavailable.")
|
||||
End Sub
|
||||
|
||||
Private Async Function UpdateTimer_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) As Task Handles UpdateTimer.Elapsed
|
||||
Private Async Sub UpdateTimer_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles UpdateTimer.Elapsed
|
||||
Try
|
||||
If _Channel Is Nothing OrElse _Channel.State <> CommunicationState.Opened Then
|
||||
Logger.Warn("⚠ UpdateTimer skipped: Channel not in Opened state [{0}]", If(_Channel IsNot Nothing, _Channel.State.ToString(), "null"))
|
||||
_IsOnline = False
|
||||
Reconnect()
|
||||
Return
|
||||
End If
|
||||
|
||||
If Not _IsOnline Then
|
||||
Logger.Debug("UpdateTimer skipped: Client is offline.")
|
||||
Return
|
||||
End If
|
||||
|
||||
Dim oTables As String() = Await _Channel.GetCachedTablesAsync()
|
||||
' ◄ NullReferenceException-Schutz: Service kann Nothing zurückgeben
|
||||
If oTables Is Nothing Then
|
||||
Logger.Warn("⚠ UpdateTimer: GetCachedTablesAsync returned Nothing.")
|
||||
_CachedTables = New List(Of String)
|
||||
Return
|
||||
End If
|
||||
_CachedTables = oTables.
|
||||
Select(Function(table) table.ToUpper).
|
||||
ToList()
|
||||
Select(Function(table) table.ToUpper).
|
||||
ToList()
|
||||
|
||||
Logger.Info("✔ Channel state: [{0}] | Active connections: [{1}] | CachedTables: [{2}]",
|
||||
_Channel.State,
|
||||
Channel.ActiveConnections,
|
||||
_CachedTables.Count)
|
||||
|
||||
If _ActiveClients.ContainsKey(_ClientId) Then
|
||||
_ActiveClients(_ClientId) = GetStatus()
|
||||
End If
|
||||
|
||||
Catch ex As TimeoutException
|
||||
' Stale TCP connection (z.B. Firewall/Citrix Idle-Timeout)
|
||||
Logger.Warn("⚠ UpdateTimer: TCP connection lost (idle timeout / firewall). Triggering reconnect...")
|
||||
_IsOnline = False
|
||||
Reconnect()
|
||||
|
||||
Catch ex As CommunicationException
|
||||
Logger.Warn("⚠ UpdateTimer: Channel faulted. Triggering reconnect...")
|
||||
_IsOnline = False
|
||||
Reconnect()
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Update of CachedTable was not successful!")
|
||||
Logger.Warn("⚠ Update of CachedTable was not successful!")
|
||||
Logger.Error(ex)
|
||||
_CachedTables = New List(Of String)
|
||||
End Try
|
||||
End Function
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Imports a file from a filepath, creating a IDB ObjectId and Filesystem Object
|
||||
@@ -460,7 +574,7 @@ Public Class Client
|
||||
Dim oResult = _Channel.ExecuteNonQuery_MSSQL_IDB(oSql)
|
||||
|
||||
If oResult.OK = False Then
|
||||
Logger.Warn("Error while deleting Term object")
|
||||
Logger.Warn("⚠ Error while IDBNewObjectData")
|
||||
Logger.Error(oResult.ErrorMessage)
|
||||
End If
|
||||
|
||||
@@ -477,7 +591,7 @@ Public Class Client
|
||||
Dim oResult = _Channel.ExecuteNonQuery_MSSQL_IDB(oDELSQL)
|
||||
|
||||
If oResult.OK = False Then
|
||||
Logger.Warn("Error while deleting Term object")
|
||||
Logger.Warn("⚠ Error while deleting Term object")
|
||||
Logger.Error(oResult.ErrorMessage)
|
||||
End If
|
||||
|
||||
@@ -490,268 +604,351 @@ Public Class Client
|
||||
|
||||
#Region "GetDatatable"
|
||||
Public Function GetDatatableFromIDB(pSQL As String) As GetDatatableResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||||
Return _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.IDB
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDB))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDB))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function GetDatatableFromECM(pSQL As String) As GetDatatableResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||||
Return _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.ECM
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromECM))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromECM))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function GetDatatableFromConnection(pSQL As String, pConnectionId As Integer) As GetDatatableResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||||
Return _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.None,
|
||||
.ConnectionId = pConnectionId
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnection))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnection))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableFromIDBAsync(pSQL As String) As Task(Of GetDatatableResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||||
Return Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.IDB
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDBAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDBAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableFromECMAsync(pSQL As String) As Task(Of GetDatatableResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||||
Logger.Debug("GetDatatableFromECMAsync will be called with SQL [{0}]", pSQL)
|
||||
Return Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.ECM
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromECMAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromECMAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableFromConnectionAsync(pSQL As String, Optional pConnectionId As Integer = 0) As Task(Of GetDatatableResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||||
Return Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.None,
|
||||
.ConnectionId = pConnectionId
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnectionAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnectionAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
#Region "GetScalarValue"
|
||||
Public Function GetScalarValueFromIDB(pSQL As String) As GetScalarValueResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||||
Return _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.IDB
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDB))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDB))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function GetScalarValueFromECM(pSQL As String) As GetScalarValueResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||||
Return _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.ECM
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECM))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECM))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function GetScalarValueFromConnection(pSQL As String, pConnectionId As Integer) As GetScalarValueResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||||
Return _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.None,
|
||||
.ConnectionId = pConnectionId
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnection))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnection))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetScalarValueFromIDBAsync(pSQL As String) As Task(Of GetScalarValueResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||||
Return Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.IDB
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDBAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDBAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetScalarValueFromECMAsync(pSQL As String) As Task(Of GetScalarValueResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||||
Return Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.ECM
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECMAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECMAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetScalarValueFromConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of GetScalarValueResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||||
Return Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.None,
|
||||
.ConnectionId = pConnectionId
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnectionAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnectionAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
#Region "ExecuteNonQuery"
|
||||
Public Function ExecuteNonQueryFromIDB(pSQL As String) As ExecuteNonQueryResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||||
Return _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.IDB
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromIDB))
|
||||
Throw
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromIDB))
|
||||
Throw
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function ExecuteNonQueryFromECM(pSQL As String) As ExecuteNonQueryResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||||
Return _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.ECM
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECM))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECM))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function ExecuteNonQueryFromConnection(pSQL As String, pConnectionId As Integer) As ExecuteNonQueryResponse
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||||
Return _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.None,
|
||||
.ConnectionId = pConnectionId
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnection))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnection))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function ExecuteNonQueryFromIDBAsync(pSQL As String) As Task(Of ExecuteNonQueryResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||||
Return Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.IDB
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromIDBAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromIDBAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function ExecuteNonQueryFromECMAsync(pSQL As String) As Task(Of ExecuteNonQueryResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||||
Return Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.ECM
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECMAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECMAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function ExecuteNonQueryFromConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of ExecuteNonQueryResponse)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||||
Return Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||||
.SqlCommand = pSQL,
|
||||
.NamedDatabase = DatabaseName.None,
|
||||
.ConnectionId = pConnectionId
|
||||
})
|
||||
Return oResponse
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnectionAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnectionAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
|
||||
Public Function GetDatatableByName(DatatableName As String, Optional FilterExpression As String = "", Optional SortByColumn As String = "") As TableResult
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = _Channel.ReturnDatatableFromCache(DatatableName, FilterExpression, SortByColumn)
|
||||
Return oResponse
|
||||
Return _Channel.ReturnDatatableFromCache(DatatableName, FilterExpression, SortByColumn)
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableByName))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableByName))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableByNameAsync(DatatableName As String, Optional FilterExpression As String = "", Optional SortByColumn As String = "") As Task(Of TableResult)
|
||||
EnsureAvailable()
|
||||
Try
|
||||
Dim oResponse = Await _Channel.ReturnDatatableFromCacheAsync(DatatableName, FilterExpression, SortByColumn)
|
||||
Return oResponse
|
||||
Return Await _Channel.ReturnDatatableFromCacheAsync(DatatableName, FilterExpression, SortByColumn)
|
||||
Catch ex As EndpointNotFoundException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableByNameAsync))
|
||||
Catch ex As CommunicationException
|
||||
HandleCommunicationError(ex, NameOf(GetDatatableByNameAsync))
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
@@ -819,6 +1016,40 @@ Public Class Client
|
||||
Private Function GetUserName(pOverrideName) As String
|
||||
Return ObjectEx.NotNull(pOverrideName, Environment.UserName)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' Throws InvalidOperationException if the channel is not ready for calls
|
||||
''' </summary>
|
||||
Private Sub EnsureAvailable()
|
||||
If _Channel Is Nothing Then
|
||||
Throw New InvalidOperationException("Channel is not initialized. Call Connect() first.")
|
||||
End If
|
||||
|
||||
If _Channel.State <> CommunicationState.Opened Then
|
||||
Throw New InvalidOperationException($"Channel is not available. State=[{_Channel.State}]")
|
||||
End If
|
||||
|
||||
If Not _IsOnline Then
|
||||
Throw New InvalidOperationException("Client is offline.")
|
||||
End If
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' Logs the communication error, sets offline state, triggers reconnect and rethrows
|
||||
''' </summary>
|
||||
Private Sub HandleCommunicationError(ex As Exception, callerName As String)
|
||||
Select Case True
|
||||
Case TypeOf ex Is EndpointNotFoundException
|
||||
Logger.Warn("⚠ Service not reachable (EndpointNotFoundException in {0}). Triggering reconnect...", callerName)
|
||||
Case TypeOf ex Is CommunicationException
|
||||
Logger.Warn("⚠ in {0} during call. Triggering reconnect...", callerName)
|
||||
Case Else
|
||||
Logger.Warn("⚠ Unexpected exception in {0} during call. Triggering reconnect...", callerName)
|
||||
Logger.Error(ex)
|
||||
End Select
|
||||
|
||||
_IsOnline = False
|
||||
Reconnect()
|
||||
Throw ex
|
||||
End Sub
|
||||
#End Region
|
||||
|
||||
#Region "Response Classes"
|
||||
@@ -887,34 +1118,74 @@ Public Class Client
|
||||
Select Case Type
|
||||
Case AttributeTypeName.VECTOR_INTEGER
|
||||
Return ValueBigInt
|
||||
|
||||
Case AttributeTypeName.BIG_INTEGER
|
||||
Return ValueBigInt
|
||||
|
||||
Case AttributeTypeName.VECTOR_STRING
|
||||
Return ValueText
|
||||
|
||||
Case AttributeTypeName.VARCHAR
|
||||
Return ValueText
|
||||
|
||||
Case AttributeTypeName.BIT
|
||||
Return IIf(ValueBigInt = 1, True, False)
|
||||
|
||||
Case AttributeTypeName.DATE
|
||||
Return ValueDate
|
||||
|
||||
Case AttributeTypeName.DATETIME
|
||||
Return ValueDate
|
||||
|
||||
Case AttributeTypeName.DECIMAL
|
||||
Return ValueDecimal
|
||||
|
||||
Case AttributeTypeName.FLOAT
|
||||
Return ValueDecimal
|
||||
|
||||
Case Else
|
||||
Return Nothing
|
||||
End Select
|
||||
End Function
|
||||
End Class ' ← ObjectAttribute endet hier
|
||||
''' <summary>
|
||||
''' Returns a detailed status snapshot of the current client state
|
||||
''' </summary>
|
||||
Public Function GetStatus() As ClientStatus
|
||||
Return New ClientStatus() With {
|
||||
.IsOnline = _IsOnline,
|
||||
.ClientId = _ClientId, ' ← Neu
|
||||
.ClientName = _ClientName,
|
||||
.ServerAddress = Me.ServerAddress,
|
||||
.ChannelState = If(_Channel IsNot Nothing, _Channel.State.ToString(), "null"),
|
||||
.ActiveConnections = Channel.ActiveConnections,
|
||||
.CachedTableCount = _CachedTables.Count,
|
||||
.CachedTables = _CachedTables.ToList(),
|
||||
.HasClientConfig = _ClientConfig IsNot Nothing,
|
||||
.IsDisposed = _Disposed,
|
||||
.TimerEnabled = UpdateTimer.Enabled,
|
||||
.TimerIntervalSeconds = CInt(UpdateTimer.Interval / 1000),
|
||||
.Timestamp = DateTime.Now
|
||||
}
|
||||
End Function
|
||||
|
||||
Public Class ClientStatus
|
||||
Public Property IsOnline As Boolean
|
||||
Public Property ClientId As String ' ← Neu
|
||||
Public Property ClientName As String
|
||||
Public Property ServerAddress As String
|
||||
Public Property ChannelState As String
|
||||
Public Property ActiveConnections As Integer
|
||||
Public Property CachedTableCount As Integer
|
||||
Public Property CachedTables As List(Of String)
|
||||
Public Property HasClientConfig As Boolean
|
||||
Public Property IsDisposed As Boolean
|
||||
Public Property TimerEnabled As Boolean
|
||||
Public Property TimerIntervalSeconds As Integer
|
||||
Public Property Timestamp As DateTime
|
||||
|
||||
Public Overrides Function ToString() As String
|
||||
Return String.Format(
|
||||
"[ClientStatus] ClientName=[{0}] Id=[{1}] Online=[{2}] Channel=[{3}]",
|
||||
ClientName, ClientId, IsOnline, ChannelState)
|
||||
End Function
|
||||
|
||||
Public Function Client_Who_ToString() As String
|
||||
Return String.Format(
|
||||
"[ClientStatus] Client=[{0}] Id=[{1}] Online=[{2}] Server=[{3}] Channel=[{4}]",
|
||||
ClientName, ClientId, IsOnline, ServerAddress, ChannelState)
|
||||
End Function
|
||||
End Class
|
||||
|
||||
End Class
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Imports System.ServiceModel
|
||||
Imports System.Threading
|
||||
Imports System.Xml
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
|
||||
@@ -10,31 +11,65 @@ Public Class Channel
|
||||
Private ReadOnly ChannelFactory As ChannelFactory(Of IEDMIServiceChannel)
|
||||
|
||||
Public Event Reconnect As EventHandler
|
||||
' Verbindungszähler
|
||||
Private Shared _ActiveConnections As Integer = 0
|
||||
Public Shared ReadOnly Property ActiveConnections As Integer
|
||||
Get
|
||||
Return _ActiveConnections
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public Shared Function GetBinding(Optional AuthenticationMode As TcpClientCredentialType = TcpClientCredentialType.Windows) As NetTcpBinding
|
||||
Return New NetTcpBinding() With {
|
||||
.MaxReceivedMessageSize = Constants.ChannelSettings.MAX_RECEIVED_MESSAGE_SIZE,
|
||||
.MaxBufferSize = Constants.ChannelSettings.MAX_BUFFER_SIZE,
|
||||
.MaxBufferPoolSize = Constants.ChannelSettings.MAX_BUFFER_POOL_SIZE,
|
||||
.TransferMode = TransferMode.Streamed,
|
||||
.Security = New NetTcpSecurity() With {
|
||||
.Mode = SecurityMode.Transport,
|
||||
.Transport = New TcpTransportSecurity() With {
|
||||
.ClientCredentialType = AuthenticationMode
|
||||
}
|
||||
},
|
||||
.ReaderQuotas = New XmlDictionaryReaderQuotas() With {
|
||||
.MaxArrayLength = Constants.ChannelSettings.MAX_ARRAY_LENGTH,
|
||||
.MaxStringContentLength = Constants.ChannelSettings.MAX_STRING_CONTENT_LENGTH
|
||||
.MaxReceivedMessageSize = Constants.ChannelSettings.MAX_RECEIVED_MESSAGE_SIZE,
|
||||
.MaxBufferSize = Constants.ChannelSettings.MAX_BUFFER_SIZE,
|
||||
.MaxBufferPoolSize = Constants.ChannelSettings.MAX_BUFFER_POOL_SIZE,
|
||||
.ListenBacklog = Constants.ChannelSettings.MAX_CONNECTIONS,
|
||||
.MaxConnections = Constants.ChannelSettings.MAX_CONNECTIONS,
|
||||
.TransferMode = TransferMode.Streamed,
|
||||
.SendTimeout = TimeSpan.FromSeconds(30), ' ← War: 5min → Schnellere Fehlererkennung
|
||||
.ReceiveTimeout = TimeSpan.FromMinutes(10), ' Keepalive < Firewall-Timeout (3600s) ✓
|
||||
.OpenTimeout = TimeSpan.FromSeconds(30), ' ← Neu: Verbindungsaufbau begrenzen
|
||||
.CloseTimeout = TimeSpan.FromSeconds(30),
|
||||
.Security = New NetTcpSecurity() With {
|
||||
.Mode = SecurityMode.Transport,
|
||||
.Transport = New TcpTransportSecurity() With {
|
||||
.ClientCredentialType = AuthenticationMode
|
||||
}
|
||||
},
|
||||
.ReaderQuotas = New XmlDictionaryReaderQuotas() With {
|
||||
.MaxArrayLength = Constants.ChannelSettings.MAX_ARRAY_LENGTH,
|
||||
.MaxStringContentLength = Constants.ChannelSettings.MAX_STRING_CONTENT_LENGTH
|
||||
}
|
||||
}
|
||||
End Function
|
||||
|
||||
Public Sub New(pLogConfig As LogConfig, pServerAddress As ServerAddressStruct)
|
||||
MyBase.New(pLogConfig)
|
||||
ChannelFactory = GetChannelFactory(pServerAddress)
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' Closes a channel gracefully, falls back to Abort on error
|
||||
''' </summary>
|
||||
Public Shared Sub CloseChannel(pChannel As IEDMIServiceChannel)
|
||||
If pChannel Is Nothing Then Return
|
||||
|
||||
Try
|
||||
If pChannel.State = CommunicationState.Opened Then
|
||||
pChannel.Close()
|
||||
ElseIf pChannel.State = CommunicationState.Faulted OrElse
|
||||
pChannel.State = CommunicationState.Closing Then
|
||||
pChannel.Abort()
|
||||
End If
|
||||
' CommunicationState.Created / Closed → nichts tun, Zähler nicht betroffen
|
||||
Catch ex As Exception
|
||||
Try
|
||||
pChannel.Abort()
|
||||
Catch
|
||||
' Ignore
|
||||
End Try
|
||||
End Try
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' Creates a channel and adds a Faulted-Handler
|
||||
''' </summary>
|
||||
@@ -44,21 +79,45 @@ Public Class Channel
|
||||
Logger.Debug("Creating channel.")
|
||||
Dim oChannel = ChannelFactory.CreateChannel()
|
||||
|
||||
AddHandler oChannel.Faulted, Sub() RaiseEvent Reconnect(Me, Nothing)
|
||||
' Verbindung zählen beim Öffnen
|
||||
AddHandler oChannel.Opened, Sub()
|
||||
Dim oCount = Interlocked.Increment(_ActiveConnections)
|
||||
Logger.Debug("Channel opened. Active connections: [{0}]", oCount)
|
||||
End Sub
|
||||
|
||||
' Verbindung abziehen beim Schließen oder Fehler
|
||||
AddHandler oChannel.Closed, Sub()
|
||||
Dim oCount = Interlocked.Decrement(_ActiveConnections)
|
||||
Logger.Debug("Channel closed. Active connections: [{0}]", oCount)
|
||||
End Sub
|
||||
|
||||
AddHandler oChannel.Faulted, Sub()
|
||||
Dim oCount = Interlocked.Decrement(_ActiveConnections)
|
||||
Logger.Warn("Channel faulted. Active connections: [{0}]", oCount)
|
||||
RaiseEvent Reconnect(Me, Nothing)
|
||||
End Sub
|
||||
|
||||
Logger.Debug("Channel created. State=[{0}]", oChannel.State)
|
||||
Return oChannel
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Throw ex
|
||||
Throw
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Function GetChannelFactory(pServerAddress As ServerAddressStruct) As ChannelFactory(Of IEDMIServiceChannel)
|
||||
Dim oBinding = GetBinding()
|
||||
Dim oAddress = New EndpointAddress($"net.tcp://{pServerAddress.Host}:{pServerAddress.Port}/DigitalData/Services/Main")
|
||||
Logger.Debug("Creating ChannelFactory with Binding: SendTimeout=[{0}], ReceiveTimeout=[{1}], MaxConnections=[{2}], MaxBufferSize=[{3}], TransferMode=[{4}]",
|
||||
oBinding.SendTimeout,
|
||||
oBinding.ReceiveTimeout,
|
||||
oBinding.MaxConnections,
|
||||
oBinding.MaxBufferSize,
|
||||
oBinding.TransferMode)
|
||||
Dim oFactory = New ChannelFactory(Of IEDMIServiceChannel)(oBinding, oAddress)
|
||||
Return oFactory
|
||||
End Function
|
||||
|
||||
End Class
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Imports DigitalData.Modules.Database
|
||||
Imports System.Data.SqlClient
|
||||
Imports DigitalData.Modules.Database
|
||||
Imports DigitalData.Modules.EDMI.API
|
||||
Imports DigitalData.Modules.EDMI.API.Constants
|
||||
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
|
||||
@@ -78,7 +79,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableECMAsync(pSQL As String) As Task(Of DataTable)
|
||||
Return Await Task.Run(Function() GetDatatableECM(pSQL))
|
||||
Return Await GetDatatableFromServiceAsync(pSQL, Constants.DatabaseType.ECM, 0)
|
||||
End Function
|
||||
|
||||
Public Function GetDatatableIDB(pSQL As String) As DataTable
|
||||
@@ -86,7 +87,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableIDBAsync(pSQL As String) As Task(Of DataTable)
|
||||
Return Await Task.Run(Function() GetDatatableIDB(pSQL))
|
||||
Return Await GetDatatableFromServiceAsync(pSQL, Constants.DatabaseType.IDB, 0)
|
||||
End Function
|
||||
|
||||
Public Function GetDatatableWithConnection(pSQL As String, pConnectionId As Integer) As DataTable
|
||||
@@ -94,7 +95,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function GetDatatableWithConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of DataTable)
|
||||
Return Await Task.Run(Function() GetDatatableWithConnection(pSQL, pConnectionId))
|
||||
Return Await GetDatatableFromServiceAsync(pSQL, Constants.DatabaseType.None, pConnectionId)
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
@@ -104,7 +105,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function GetScalarValueECMAsync(pSQL As String) As Task(Of Object)
|
||||
Return Await Task.Run(Function() GetScalarValueECM(pSQL))
|
||||
Return Await GetScalarValueFromServiceAsync(pSQL, Constants.DatabaseType.ECM, 0)
|
||||
End Function
|
||||
|
||||
Public Function GetScalarValueIDB(pSQL As String) As Object
|
||||
@@ -112,7 +113,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function GetScalarValueIDBAsync(pSQL As String) As Task(Of Object)
|
||||
Return Await Task.Run(Function() GetScalarValueIDB(pSQL))
|
||||
Return Await GetScalarValueFromServiceAsync(pSQL, Constants.DatabaseType.IDB, 0)
|
||||
End Function
|
||||
|
||||
Public Function GetScalarValueWithConnection(pSQL As String, pConnectionId As Integer) As Object
|
||||
@@ -120,7 +121,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function GetScalarValueWithConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of Object)
|
||||
Return Await Task.Run(Function() GetScalarValueWithConnection(pSQL, pConnectionId))
|
||||
Return Await GetScalarValueFromServiceAsync(pSQL, Constants.DatabaseType.None, pConnectionId)
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
@@ -130,7 +131,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function ExecuteNonQueryECMAsync(pSQL As String) As Task(Of Boolean)
|
||||
Return Await Task.Run(Function() ExecuteNonQueryECM(pSQL))
|
||||
Return Await ExecuteNonQueryFromServiceAsync(pSQL, Constants.DatabaseType.ECM, 0)
|
||||
End Function
|
||||
|
||||
Public Function ExecuteNonQueryIDB(pSQL As String) As Boolean
|
||||
@@ -138,7 +139,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function ExecuteNonQueryIDBAsync(pSQL As String) As Task(Of Boolean)
|
||||
Return Await Task.Run(Function() ExecuteNonQueryIDB(pSQL))
|
||||
Return Await ExecuteNonQueryFromServiceAsync(pSQL, Constants.DatabaseType.IDB, 0)
|
||||
End Function
|
||||
|
||||
Public Function ExecuteNonQueryWithConnection(pSQL As String, pConnectionId As Integer) As Boolean
|
||||
@@ -146,7 +147,7 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Public Async Function ExecuteNonQueryWithConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of Boolean)
|
||||
Return Await Task.Run(Function() ExecuteNonQueryWithConnection(pSQL, pConnectionId))
|
||||
Return Await ExecuteNonQueryFromServiceAsync(pSQL, Constants.DatabaseType.None, pConnectionId)
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
@@ -187,33 +188,34 @@ Public Class DatabaseWithFallback
|
||||
Try
|
||||
Dim oResult As DataTable = Nothing
|
||||
Dim oTableResult As TableResult = Nothing
|
||||
|
||||
_Logger.Debug("GetDatatable: Fetching datatable [{0}] , Filter Expression [{1}], Sort By Column [{2}], Force Fallback [{3}]",
|
||||
pDataTableName, pFilterExpression, pSortByColumn, pForceFallback)
|
||||
' If there is no client, we assume there is no service (configured)
|
||||
If _Client Is Nothing Then
|
||||
_Logger.Debug("Client is empty, falling back to direct database access.")
|
||||
_Logger.Debug("GetDatatable: Client is empty, falling back to direct database access.")
|
||||
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
|
||||
End If
|
||||
|
||||
' If ForceFallback flag is set, we go to database immediately
|
||||
If pForceFallback Or _ClientConfig.ForceDirectDatabaseAccess Then
|
||||
_Logger.Debug("ForceFallback is True, falling back to direct database access.")
|
||||
_Logger.Debug("GetDatatable: ForceFallback is True, falling back to direct database access.")
|
||||
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
|
||||
End If
|
||||
|
||||
' If the table is not cached, we try going through the service
|
||||
If Not IsTableCached(pDataTableName) Then
|
||||
_Logger.Debug("Datatable is not chached, fetching data from service.")
|
||||
_Logger.Debug("GetDatatable: Datatable [{0}] is not chached, fetching data from service.", pDataTableName)
|
||||
Return GetDatatableFromService(pFallbackSQL, pFallbackType, pConnectionId)
|
||||
End If
|
||||
|
||||
' If there is a proper ConnectionId, we try going through the service
|
||||
If pConnectionId > 0 Then
|
||||
_Logger.Debug("ConnectionId is set, fetching data from service.")
|
||||
_Logger.Debug("GetDatatable: ConnectionId is set, fetching data from service.")
|
||||
Return GetDatatableFromService(pFallbackSQL, pFallbackType, pConnectionId)
|
||||
End If
|
||||
|
||||
Try
|
||||
_Logger.Debug("Datatable is chached, fetching data from cache.")
|
||||
_Logger.Debug("GetDatatable: Datatable is chached, fetching data from cache.")
|
||||
oTableResult = _Client.GetDatatableByName(pDataTableName, pFilterExpression, pSortByColumn)
|
||||
Catch ex As Exception
|
||||
_Logger.Error(ex)
|
||||
@@ -221,9 +223,10 @@ Public Class DatabaseWithFallback
|
||||
End Try
|
||||
|
||||
If oTableResult Is Nothing OrElse oTableResult.OK = False Then
|
||||
_Logger.Warn("Datatable [{0}] could not be fetched from AppServer Cache. Falling back to direct Database Access.", pDataTableName)
|
||||
_Logger.Warn("⚠ GetDatatable: Datatable [{0}] could not be fetched from AppServer Cache. Falling back to direct Database Access.", pDataTableName)
|
||||
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
|
||||
Else
|
||||
_Logger.Debug("✔ GetDatatable: Datatable [{0}] fetched from AppServer Cache.", pDataTableName)
|
||||
Return oTableResult.Table
|
||||
End If
|
||||
|
||||
@@ -276,11 +279,13 @@ Public Class DatabaseWithFallback
|
||||
|
||||
' If there is no client, we assume there is no service (configured)
|
||||
If _Client Is Nothing Then
|
||||
_Logger.Debug("ExecuteNonQuery - Client is empty, falling back to direct database access.")
|
||||
Return ExecuteNonQueryFromDatabase(pSQL, pDatabaseType, pConnectionId)
|
||||
End If
|
||||
|
||||
' If ForceFallback flag is set, we go to database immediately
|
||||
If pForceFallback Or _ClientConfig.ForceDirectDatabaseAccess Then
|
||||
_Logger.Debug("ExecuteNonQuery - ForceFallback is set, falling back to direct database access.")
|
||||
Return ExecuteNonQueryFromDatabase(pSQL, pDatabaseType, pConnectionId)
|
||||
End If
|
||||
|
||||
@@ -294,7 +299,9 @@ Public Class DatabaseWithFallback
|
||||
End Function
|
||||
|
||||
Private Function IsTableCached(pName As String) As Boolean
|
||||
_Logger.Debug("IsTableCached: Checking if table [{0}] is cached.", pName)
|
||||
If _Client Is Nothing Then
|
||||
_Logger.Warn("⚠ IsTableCached: Client is nothing, cannot check if table is cached.")
|
||||
Return False
|
||||
End If
|
||||
|
||||
@@ -303,42 +310,74 @@ Public Class DatabaseWithFallback
|
||||
|
||||
Private Function GetDatatableFromService(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As DataTable
|
||||
Try
|
||||
_Logger.Debug("GetDatatableFromService: Fetching data from service [{0}] with Connection Id [{1}] and Command [{2}]", DatabaseType.ToString, pConnectionId, pSQLCommand)
|
||||
Dim oResult As GetDatatableResponse = Nothing
|
||||
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.ECM
|
||||
oResult = _Client.GetDatatableFromECM(pSQLCommand)
|
||||
|
||||
Case Constants.DatabaseType.IDB
|
||||
oResult = _Client.GetDatatableFromIDB(pSQLCommand)
|
||||
|
||||
Case Else
|
||||
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
End Select
|
||||
|
||||
If oResult Is Nothing Then
|
||||
Throw New ApplicationException("Unexpected server error ocurred!")
|
||||
End If
|
||||
|
||||
If oResult.OK = False Then
|
||||
Throw New ApplicationException(oResult.ErrorMessage)
|
||||
If oResult Is Nothing OrElse oResult.OK = False Then
|
||||
_Logger.Warn("⚠ GetDatatableFromService: Service returned invalid response [{0}]. Falling back to direct database access.", If(oResult Is Nothing, "null", oResult.ErrorMessage))
|
||||
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
End If
|
||||
|
||||
Return oResult.Table
|
||||
|
||||
Catch ex As InvalidOperationException
|
||||
_Logger.Warn("⚠ GetDatatableFromService skipped: [{0}] Falling back to direct database access.", ex.Message)
|
||||
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("GetDatatableFromService failed. Falling back to direct database access.")
|
||||
_Logger.Warn("⚠ GetDatatableFromService failed. Falling back to direct database access.")
|
||||
_Logger.Error(ex)
|
||||
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Private Async Function GetDatatableFromServiceAsync(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Task(Of DataTable)
|
||||
Dim oFallback As Boolean = False
|
||||
_Logger.Debug("GetDatatableFromServiceAsync: GetDatatableFromServiceAsync called with SQL [{0}], DatabaseType [{1}], ConnectionId [{2}]", pSQLCommand, DatabaseType.ToString, pConnectionId)
|
||||
If _Client Is Nothing OrElse _ClientConfig?.ForceDirectDatabaseAccess Then
|
||||
Return Await Task.Run(Function() GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId))
|
||||
End If
|
||||
|
||||
Dim oResult As GetDatatableResponse = Nothing
|
||||
Try
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.ECM
|
||||
oResult = Await _Client.GetDatatableFromECMAsync(pSQLCommand)
|
||||
Case Constants.DatabaseType.IDB
|
||||
oResult = Await _Client.GetDatatableFromIDBAsync(pSQLCommand)
|
||||
Case Else
|
||||
oResult = Await _Client.GetDatatableFromConnectionAsync(pSQLCommand, pConnectionId)
|
||||
End Select
|
||||
|
||||
If oResult Is Nothing OrElse oResult.OK = False Then
|
||||
_Logger.Warn("⚠ GetDatatableFromServiceAsync failed. Falling back to direct database access.")
|
||||
oFallback = True
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("⚠ GetDatatableFromServiceAsync failed. Falling back to direct database access.")
|
||||
_Logger.Error(ex)
|
||||
oFallback = True
|
||||
End Try
|
||||
|
||||
If oFallback Then
|
||||
Return Await Task.Run(Function() GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId))
|
||||
End If
|
||||
|
||||
Return oResult.Table
|
||||
End Function
|
||||
Private Function GetDatatableFromDatabase(pSQLCommand As String, pDatabaseType As Constants.DatabaseType, pConnectionId As Integer) As DataTable
|
||||
Try
|
||||
_Logger.Debug("Fetching data from database [{0}] with Connection Id [{0}]", pDatabaseType.ToString, pConnectionId)
|
||||
_Logger.Debug("GetDatatableFromDatabase: Fetching data from database [{0}] with Connection Id [{1}] and Command [{2}]", pDatabaseType.ToString, pConnectionId, pSQLCommand)
|
||||
|
||||
Select Case pDatabaseType
|
||||
Case Constants.DatabaseType.IDB
|
||||
@@ -361,35 +400,68 @@ Public Class DatabaseWithFallback
|
||||
|
||||
End Try
|
||||
End Function
|
||||
Private Async Function GetScalarValueFromServiceAsync(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Task(Of Object)
|
||||
Dim oFallback As Boolean = False
|
||||
|
||||
_Logger.Debug("GetScalarValueFromServiceAsync called with SQL [{0}], DatabaseType [{1}], ConnectionId [{2}]", pSQLCommand, DatabaseType.ToString, pConnectionId)
|
||||
|
||||
If _Client Is Nothing OrElse _ClientConfig?.ForceDirectDatabaseAccess Then
|
||||
Return Await Task.Run(Function() GetScalarValueFromDatabase(pSQLCommand, DatabaseType, pConnectionId))
|
||||
End If
|
||||
|
||||
Dim oResult As GetScalarValueResponse = Nothing
|
||||
Try
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.ECM
|
||||
oResult = Await _Client.GetScalarValueFromECMAsync(pSQLCommand)
|
||||
Case Constants.DatabaseType.IDB
|
||||
oResult = Await _Client.GetScalarValueFromIDBAsync(pSQLCommand)
|
||||
Case Else
|
||||
oResult = Await _Client.GetScalarValueFromConnectionAsync(pSQLCommand, pConnectionId)
|
||||
End Select
|
||||
|
||||
If oResult Is Nothing OrElse oResult.OK = False Then
|
||||
_Logger.Warn("⚠ GetScalarValueFromServiceAsync failed. Falling back to direct database access.")
|
||||
oFallback = True
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("⚠ GetScalarValueFromServiceAsync failed. Falling back to direct database access.")
|
||||
_Logger.Error(ex)
|
||||
oFallback = True
|
||||
End Try
|
||||
|
||||
If oFallback Then
|
||||
Return Await Task.Run(Function() GetScalarValueFromDatabase(pSQLCommand, DatabaseType, pConnectionId))
|
||||
End If
|
||||
|
||||
Return oResult.Scalar
|
||||
End Function
|
||||
Private Function GetScalarValueFromService(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Object
|
||||
Try
|
||||
Dim oResult As GetScalarValueResponse = Nothing
|
||||
|
||||
_Logger.Debug("GetScalarValueFromService [{0}] with Connection Id [{1}] and Command [{2}]", DatabaseType.ToString, pConnectionId, pSQLCommand)
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.ECM
|
||||
oResult = _Client.GetScalarValueFromECM(pSQLCommand)
|
||||
|
||||
Case Constants.DatabaseType.IDB
|
||||
oResult = _Client.GetScalarValueFromIDB(pSQLCommand)
|
||||
|
||||
Case Else
|
||||
Return GetScalarValueFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
End Select
|
||||
|
||||
If oResult Is Nothing Then
|
||||
Throw New ApplicationException("Unexpected server error ocurred!")
|
||||
End If
|
||||
|
||||
If oResult.OK = False Then
|
||||
Throw New ApplicationException(oResult.ErrorMessage)
|
||||
If oResult Is Nothing OrElse oResult.OK = False Then
|
||||
_Logger.Warn("⚠ GetScalarValueFromService: Service returned invalid response [{0}]. Falling back to direct database access.", If(oResult Is Nothing, "null", oResult.ErrorMessage))
|
||||
Return GetScalarValueFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
End If
|
||||
|
||||
Return oResult.Scalar
|
||||
|
||||
Catch ex As InvalidOperationException
|
||||
_Logger.Warn("⚠ GetScalarValueFromService skipped: [{0}] Falling back to direct database access.", ex.Message)
|
||||
Return GetScalarValueFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("GetScalarValueFromService failed. Falling back to direct database access.")
|
||||
_Logger.Warn("⚠ GetScalarValueFromService failed. Falling back to direct database access.")
|
||||
_Logger.Error(ex)
|
||||
Return GetScalarValueFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
@@ -399,6 +471,7 @@ Public Class DatabaseWithFallback
|
||||
|
||||
Private Function GetScalarValueFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Object
|
||||
Try
|
||||
_Logger.Debug("DBwFF GetScalarValueFromDatabase [{0}] with Connection Id [{1}] and Command [{2}]", DatabaseType.ToString, pConnectionId, pSQLCommand)
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.IDB
|
||||
Return _DatabaseIDB.GetScalarValue(pSQLCommand)
|
||||
@@ -419,35 +492,68 @@ Public Class DatabaseWithFallback
|
||||
|
||||
End Try
|
||||
End Function
|
||||
Private Async Function ExecuteNonQueryFromServiceAsync(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Task(Of Boolean)
|
||||
Dim oFallback As Boolean = False
|
||||
|
||||
_Logger.Debug("ExecuteNonQueryFromServiceAsync called with SQL [{0}], DatabaseType [{1}], ConnectionId [{2}]", pSQLCommand, DatabaseType.ToString, pConnectionId)
|
||||
|
||||
If _Client Is Nothing OrElse _ClientConfig?.ForceDirectDatabaseAccess Then
|
||||
Return Await Task.Run(Function() ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId))
|
||||
End If
|
||||
|
||||
Dim oResult As ExecuteNonQueryResponse = Nothing
|
||||
Try
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.ECM
|
||||
oResult = Await _Client.ExecuteNonQueryFromECMAsync(pSQLCommand)
|
||||
Case Constants.DatabaseType.IDB
|
||||
oResult = Await _Client.ExecuteNonQueryFromIDBAsync(pSQLCommand)
|
||||
Case Else
|
||||
oResult = Await _Client.ExecuteNonQueryFromConnectionAsync(pSQLCommand, pConnectionId)
|
||||
End Select
|
||||
|
||||
If oResult Is Nothing OrElse oResult.OK = False Then
|
||||
_Logger.Warn("⚠ ExecuteNonQueryFromServiceAsync failed. Falling back to direct database access.")
|
||||
oFallback = True
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("⚠ ExecuteNonQueryFromServiceAsync failed. Falling back to direct database access.")
|
||||
_Logger.Error(ex)
|
||||
oFallback = True
|
||||
End Try
|
||||
|
||||
If oFallback Then
|
||||
Return Await Task.Run(Function() ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId))
|
||||
End If
|
||||
|
||||
Return oResult.Result
|
||||
End Function
|
||||
Private Function ExecuteNonQueryFromService(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Boolean
|
||||
Try
|
||||
Dim oResult As ExecuteNonQueryResponse = Nothing
|
||||
|
||||
_Logger.Debug("ExecuteNonQueryFromService [{0}] with Connection Id [{1}] and Command [{2}]", DatabaseType.ToString, pConnectionId, pSQLCommand)
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.ECM
|
||||
oResult = _Client.ExecuteNonQueryFromECM(pSQLCommand)
|
||||
|
||||
Case Constants.DatabaseType.IDB
|
||||
oResult = _Client.ExecuteNonQueryFromIDB(pSQLCommand)
|
||||
|
||||
Case Else
|
||||
Return ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
End Select
|
||||
|
||||
If oResult Is Nothing Then
|
||||
Throw New ApplicationException("Unexpected server error ocurred!")
|
||||
End If
|
||||
|
||||
If oResult.OK = False Then
|
||||
Throw New ApplicationException(oResult.ErrorMessage)
|
||||
If oResult Is Nothing OrElse oResult.OK = False Then
|
||||
_Logger.Warn("⚠ ExecuteNonQueryFromService: Service returned invalid response [{0}]. Falling back to direct database access.", If(oResult Is Nothing, "null", oResult.ErrorMessage))
|
||||
Return ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
End If
|
||||
|
||||
Return oResult.Result
|
||||
|
||||
Catch ex As InvalidOperationException
|
||||
_Logger.Warn("⚠ ExecuteNonQueryFromService skipped: [{0}] Falling back to direct database access.", ex.Message)
|
||||
Return ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("ExecuteNonQueryFromService failed. Falling back to direct database access.")
|
||||
_Logger.Warn("⚠ ExecuteNonQueryFromService failed. Falling back to direct database access.")
|
||||
_Logger.Error(ex)
|
||||
Return ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
|
||||
|
||||
@@ -456,6 +562,8 @@ Public Class DatabaseWithFallback
|
||||
|
||||
Private Function ExecuteNonQueryFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Boolean
|
||||
Try
|
||||
_Logger.Debug("ExecuteNonQueryFromDatabase [{0}] with Connection Id [{1}] and Command [{2}]", DatabaseType.ToString, pConnectionId, pSQLCommand)
|
||||
|
||||
Select Case DatabaseType
|
||||
Case Constants.DatabaseType.IDB
|
||||
Return _DatabaseIDB.ExecuteNonQuery(pSQLCommand)
|
||||
|
||||
@@ -25,7 +25,7 @@ Namespace Modules.IDB
|
||||
Return True
|
||||
End If
|
||||
|
||||
Logger.Warn("Error while setting Attribute Value: [{0}]", oResponse.ErrorMessage)
|
||||
Logger.Warn("⚠ Error while setting Attribute Value: [{0}]", oResponse.ErrorMessage)
|
||||
Return False
|
||||
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
|
||||
<Assembly: AssemblyCompany("Digital Data")>
|
||||
<Assembly: AssemblyProduct("EDMIAPI")>
|
||||
<Assembly: AssemblyCopyright("Copyright © 2026")>
|
||||
<Assembly: AssemblyTrademark("2.0.0")>
|
||||
<Assembly: AssemblyTrademark("2.7.0")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
|
||||
' übernehmen, indem Sie "*" eingeben:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2.0.0.0")>
|
||||
<Assembly: AssemblyVersion("2.7.0.0")>
|
||||
<Assembly: AssemblyFileVersion("1.6.1.1")>
|
||||
|
||||
Reference in New Issue
Block a user