Es wurde eine neue Funktion `GetServiceStatus` zur Klasse `Client` hinzugefügt, die einen Live-Monitoring-Snapshot vom Service abruft. In `ClientStatus` wurde die Eigenschaft `ClientId` als reguläre Eigenschaft hinzugefügt. In `Reference.vb` wurden zahlreiche neue Methoden für Datenbank- und Dateioperationen implementiert, sowohl synchron als auch asynchron. Dazu gehören Funktionen wie `ReturnDatatable`, `NewFile`, `GetFileByObjectId` und `TestObjectIdExists`. Bestehende Methoden wurden überarbeitet, um die Lesbarkeit zu verbessern. Die Datei `LogConfig.vb` wurde angepasst, indem eine Debug-Log-Meldung entfernt wurde. In `AssemblyInfo.vb` wurde die Version auf `2.7.0.0` aktualisiert. Ein neues Projekt `EDMIService` wurde zur Lösung hinzugefügt, einschließlich der entsprechenden Build-Konfigurationen.
1203 lines
45 KiB
VB.net
1203 lines
45 KiB
VB.net
Imports System.IO
|
||
Imports System.ServiceModel
|
||
Imports DigitalData.Modules.Base
|
||
Imports DigitalData.Modules.EDMI.API.Constants
|
||
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
|
||
Imports DigitalData.Modules.EDMI.API.Rights
|
||
Imports DigitalData.Modules.Logging
|
||
|
||
Public Class Client
|
||
Implements IDisposable
|
||
' Constants
|
||
Private Const UPDATE_INTERVAL_IN_MINUTES As Integer = 1
|
||
|
||
Private Const KIND_TYPE_DOC = "DOC"
|
||
|
||
' Helper Classes
|
||
Private ReadOnly LogConfig As LogConfig
|
||
Private ReadOnly Logger As Logger
|
||
Private ReadOnly ChannelManager As Channel
|
||
|
||
' Runtime Variables
|
||
Private _ServerAddress As ServerAddressStruct
|
||
Private _ClientConfig As GlobalStateClientConfiguration
|
||
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
|
||
Get
|
||
Return _CachedTables
|
||
End Get
|
||
End Property
|
||
|
||
Public ReadOnly Property ClientConfig As GlobalStateClientConfiguration
|
||
Get
|
||
If _ClientConfig Is Nothing Then
|
||
Throw New ApplicationException("ClientConfig is empty! Please connect to the service before accessing this property")
|
||
End If
|
||
|
||
Return _ClientConfig
|
||
End Get
|
||
End Property
|
||
|
||
Public ReadOnly Property IsOnline As Boolean
|
||
Get
|
||
Return _IsOnline
|
||
End Get
|
||
End Property
|
||
|
||
Public ReadOnly Property ServerAddress As String
|
||
Get
|
||
Return $"{_ServerAddress.Host}:{_ServerAddress.Port}"
|
||
End Get
|
||
End Property
|
||
|
||
''' <summary>
|
||
''' Parse a IPAddress:Port String into its parts
|
||
''' </summary>
|
||
''' <param name="AddressWithOptionalPort">A Server Address, for example: 192.168.1.50, 192.168.1.50:9000, 192.168.1.50;9000</param>
|
||
Public Shared Function ParseServiceAddress(AddressWithOptionalPort As String) As Tuple(Of String, Integer)
|
||
Dim oConnection As New Connection()
|
||
Dim oAddress As ServerAddressStruct = oConnection.ParseServiceAddress(AddressWithOptionalPort)
|
||
|
||
Return New Tuple(Of String, Integer)(oAddress.Host, oAddress.Port)
|
||
End Function
|
||
|
||
''' <summary>
|
||
''' Creates a new EDMI Client object
|
||
''' </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>
|
||
''' <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()
|
||
|
||
Try
|
||
Dim oConnection = New Connection()
|
||
_ServerAddress = oConnection.ParseServiceAddress(pServiceAdress)
|
||
ChannelManager = New Channel(pLogConfig, _ServerAddress)
|
||
AddHandler ChannelManager.Reconnect, AddressOf Reconnect
|
||
|
||
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>
|
||
''' Creates a new EDMI Client object
|
||
''' </summary>
|
||
''' <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>
|
||
''' <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()
|
||
|
||
Try
|
||
Dim oConnection = New Connection()
|
||
_ServerAddress = oConnection.ParseServiceAddress(pIPAddress, pPortNumber)
|
||
ChannelManager = New Channel(pLogConfig, _ServerAddress)
|
||
AddHandler ChannelManager.Reconnect, AddressOf Reconnect
|
||
|
||
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>
|
||
''' <returns>True if connection was successful, false otherwise</returns>
|
||
Public Function Connect() As Boolean
|
||
Try
|
||
_Channel = ChannelManager.GetChannel()
|
||
|
||
Logger.Debug("Opening channel..")
|
||
_Channel.Open()
|
||
|
||
Dim oResponse = _Channel.GetClientConfig()
|
||
If oResponse.OK Then
|
||
_ClientConfig = oResponse.ClientConfig
|
||
Else
|
||
Logger.Warn("⚠Client Configuration could not be loaded: [{0}]", oResponse.ErrorMessage)
|
||
End If
|
||
|
||
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
|
||
|
||
Logger.Error(ex)
|
||
Return False
|
||
End Try
|
||
End Function
|
||
|
||
''' <summary>
|
||
''' Aborts the channel and creates a new connection
|
||
''' </summary>
|
||
Public Async Sub Reconnect()
|
||
Logger.Warn("⚠ Connection faulted. Trying to reconnect..")
|
||
|
||
Dim oRetryDelays = {2, 5, 15, 30}
|
||
|
||
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 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()
|
||
|
||
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.Error(ex)
|
||
_CachedTables = New List(Of String)
|
||
End Try
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' Imports a file from a filepath, creating a IDB ObjectId and Filesystem Object
|
||
''' </summary>
|
||
''' <param name="pObjectStoreName">Type of ObjectStore. Can be WORK or ARCHIVE.</param>
|
||
''' <param name="pIDBDoctypeId">Business entity that the new file object should belong to.</param>
|
||
''' <param name="pImportOptions">Other file import options</param>
|
||
''' <exception cref="FileNotFoundException">When local filepath was not found</exception>
|
||
''' <exception cref="ApplicationException">When there was a error in the Service</exception>
|
||
''' <returns>The ObjectId of the newly generated filesystem object</returns>
|
||
Public Async Function NewFileAsync(pFilePath As String, pObjectStoreName As String, pObjectKind As String, pIDBDoctypeId As Long, Optional pImportOptions As Options.NewFileOptions = Nothing) As Task(Of Long)
|
||
Try
|
||
Dim oNewFile As New Modules.IDB.NewFile(LogConfig, _Channel)
|
||
Return Await oNewFile.RunAsync(pFilePath, pObjectStoreName, pObjectKind, pIDBDoctypeId, pImportOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function UpdateFileAsync(pObjectId As Long, pFilePath As String, Optional pImportOptions As Options.UpdateFileOptions = Nothing) As Task(Of Long)
|
||
Try
|
||
Dim oUpdateFile As New Modules.IDB.UpdateFile(LogConfig, _Channel)
|
||
Return Await oUpdateFile.RunAsync(pFilePath, pObjectId, pImportOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function SetObjectStateAsync(pObjectId As Long, pState As String, Optional pOptions As Options.SetObjectStateOptions = Nothing) As Task(Of Boolean)
|
||
Try
|
||
Dim oSetObjectState As New Modules.IDB.SetObjectState(LogConfig, _Channel)
|
||
Return Await oSetObjectState.RunAsync(pObjectId, pState, pOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return False
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function SetAttributeValueAsync(pObjectId As Long, pName As String, pValue As Object, Optional pOptions As Options.SetAttributeValueOptions = Nothing) As Task(Of Boolean)
|
||
Try
|
||
Dim oSetAttributeValue As New Modules.IDB.SetAttributeValue(LogConfig, _Channel)
|
||
Return Await oSetAttributeValue.RunAsync(pObjectId, pName, pValue, pOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return False
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function CheckOutFile(pObjectId As Long, pComment As String, Optional pOptions As Options.CheckOutInOptions = Nothing) As Task(Of Long)
|
||
Try
|
||
Dim oCheckOutFile As New Modules.IDB.CheckOutFile(LogConfig, _Channel)
|
||
Return Await oCheckOutFile.RunAsync(pObjectId, pComment, pOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function CheckOutFile(pObjectId As Long, Optional pOptions As Options.CheckOutInOptions = Nothing) As Task(Of Long)
|
||
Try
|
||
Dim oCheckOutFile As New Modules.IDB.CheckOutFile(LogConfig, _Channel)
|
||
Return Await oCheckOutFile.RunAsync(pObjectId, String.Empty, pOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function CheckInFile(pObjectId As Long, Optional pOptions As Options.CheckOutInOptions = Nothing) As Task(Of Long)
|
||
Try
|
||
Dim oCheckInFile As New Modules.IDB.CheckInFile(LogConfig, _Channel)
|
||
Return Await oCheckInFile.RunAsync(pObjectId, pOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function ImportFileAsync(
|
||
pFilePath As String,
|
||
pAttributeValues As List(Of UserAttributeValue),
|
||
pObjectStoreName As String,
|
||
pObjectKind As String,
|
||
pIDBDoctypeId As String,
|
||
Optional pImportOptions As Options.ImportFileOptions = Nothing) As Task(Of ImportFileResponse)
|
||
Try
|
||
Dim oImportFile As New Modules.IDB.ImportFile(LogConfig, _Channel)
|
||
Return Await oImportFile.RunAsync(pFilePath, pAttributeValues, pObjectStoreName, pObjectKind, pIDBDoctypeId, pImportOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function Globix_ImportFileAsync(
|
||
pFilePath As String,
|
||
pProfileId As Integer,
|
||
pAttributeValues As List(Of UserAttributeValue),
|
||
pObjectStoreName As String,
|
||
pObjectKind As String,
|
||
pIDBDoctypeId As String,
|
||
Optional pImportOptions As Options.ImportFileOptions = Nothing) As Task(Of Globix_ImportFileResponse)
|
||
Try
|
||
Dim oImportFile As New Modules.Globix.ImportFile(LogConfig, _Channel)
|
||
Return Await oImportFile.RunAsync(pFilePath, pProfileId, pAttributeValues, pObjectStoreName, pObjectKind, pIDBDoctypeId, pImportOptions)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Function Zooflow_GetFileObject(pObjectId As Long, pLoadFileContents As Boolean) As FileObject
|
||
Try
|
||
Dim oGetFileObject As New Modules.Zooflow.GetFileObject(LogConfig, _Channel)
|
||
Dim oFileObject = oGetFileObject.Run(pObjectId, pLoadFileContents)
|
||
Return oFileObject
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
End Try
|
||
End Function
|
||
|
||
|
||
Public Async Function ZooFlow_GetFileObjectAsync(pObjectId As Long, pLoadFileContents As Boolean) As Task(Of FileObject)
|
||
Try
|
||
Dim oGetFileObject As New Modules.Zooflow.GetFileObject(LogConfig, Me)
|
||
Dim oFileObject = Await oGetFileObject.RunAsync(pObjectId, pLoadFileContents)
|
||
Return oFileObject
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
End Try
|
||
End Function
|
||
''' <summary>
|
||
'''
|
||
''' </summary>
|
||
''' <param name="pObjectId"></param>
|
||
''' <param name="pAttributeName"></param>
|
||
''' <param name="pOptions"></param>
|
||
''' <returns></returns>
|
||
Public Function GetVariableValue(pObjectId As Long, pAttributeName As String, Optional pOptions As Options.GetVariableValueOptions = Nothing) As VariableValue
|
||
If pOptions Is Nothing Then
|
||
pOptions = New Options.GetVariableValueOptions()
|
||
End If
|
||
|
||
Try
|
||
Dim oArgs = New GetAttributeValueRequest With {
|
||
.ObjectId = pObjectId,
|
||
.AttributeName = pAttributeName,
|
||
.User = New UserState() With {
|
||
.UserName = pOptions.Username,
|
||
.Language = pOptions.Language
|
||
}
|
||
}
|
||
Dim oResponse = _Channel.GetAttributeValue(oArgs)
|
||
If oResponse.OK = False Then
|
||
Return New VariableValue()
|
||
|
||
End If
|
||
|
||
Return New VariableValue(oResponse.Value)
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return New VariableValue()
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Private Function GetValueByType(pRow As DataRow, pTypeString As String) As Object
|
||
Try
|
||
Dim oAttributeValue As Object
|
||
|
||
Select Case pTypeString
|
||
Case Constants.AttributeTypeName.BIT
|
||
oAttributeValue = pRow.Item("ValueBigInt")
|
||
|
||
Case Constants.AttributeTypeName.BIG_INTEGER
|
||
oAttributeValue = pRow.Item("ValueBigInt")
|
||
|
||
Case Constants.AttributeTypeName.DATE
|
||
oAttributeValue = pRow.Item("ValueDate")
|
||
|
||
Case Constants.AttributeTypeName.DATETIME
|
||
oAttributeValue = pRow.Item("ValueDate")
|
||
|
||
Case Constants.AttributeTypeName.DECIMAL
|
||
oAttributeValue = pRow.Item("ValueDecimal")
|
||
|
||
Case Constants.AttributeTypeName.FLOAT
|
||
oAttributeValue = pRow.Item("ValueDecimal")
|
||
|
||
Case Constants.AttributeTypeName.VARCHAR
|
||
oAttributeValue = pRow.Item("ValueText")
|
||
|
||
Case Constants.AttributeTypeName.VECTOR_INTEGER
|
||
oAttributeValue = pRow.Item("ValueBigInt")
|
||
|
||
Case Constants.AttributeTypeName.VECTOR_STRING
|
||
oAttributeValue = pRow.Item("ValueText")
|
||
|
||
Case Else
|
||
oAttributeValue = Nothing
|
||
End Select
|
||
|
||
Return oAttributeValue
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Private Function GetAttributesForObject(pObjectId As Long, pLanguage As String) As List(Of ObjectAttribute)
|
||
Dim oAttributes As New List(Of ObjectAttribute)
|
||
|
||
Try
|
||
Dim oResult As TableResult = _Channel.ReturnDatatable_MSSQL_IDB($"EXEC [PRIDB_GET_VALUE_DT] {pObjectId}, '{pLanguage}'")
|
||
|
||
If oResult.OK = False Then
|
||
Throw New ApplicationException(oResult.ErrorMessage)
|
||
End If
|
||
|
||
If oResult.Table Is Nothing OrElse oResult.Table.Rows.Count = 0 Then
|
||
Return Nothing
|
||
End If
|
||
|
||
For Each oRow As DataRow In oResult.Table.Rows
|
||
Dim oAttribute As New ObjectAttribute With {
|
||
.Id = oRow.Item("AttributeId"),
|
||
.Title = oRow.Item("AttributeTitle"),
|
||
.Type = oRow.Item("AttributeType"),
|
||
.ValueBigInt = oRow.ItemEx(Of Object)("ValueBigInt", Nothing),
|
||
.ValueDate = oRow.ItemEx(Of Object)("ValueDate", Nothing),
|
||
.ValueDecimal = oRow.ItemEx(Of Object)("ValueDecimal", Nothing),
|
||
.ValueText = oRow.ItemEx(Of Object)("ValueText", Nothing)
|
||
}
|
||
|
||
oAttributes.Add(oAttribute)
|
||
Next
|
||
|
||
Return oAttributes
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
End Try
|
||
End Function
|
||
|
||
Private Function NewObjectData(pObjectId As Long, pAttributeName As String, pValue As Object, pOptions As Options.NewObjectOptions)
|
||
If pOptions Is Nothing Then
|
||
pOptions = New Options.NewObjectOptions()
|
||
End If
|
||
|
||
Dim oLanguage = GetUserLanguage(pOptions.Language)
|
||
Dim oUsername = GetUserName(pOptions.Username)
|
||
|
||
Dim oSql = $"DECLARE @NEW_OBJ_MD_ID BIGINT
|
||
EXEC PRIDB_NEW_OBJ_DATA({pObjectId}, '{pAttributeName}', '{oUsername}', '{pValue}', '{oLanguage}', 0, @OMD_ID = @NEW_OBJ_MD_ID OUTPUT)"
|
||
Dim oResult = _Channel.ExecuteNonQuery_MSSQL_IDB(oSql)
|
||
|
||
If oResult.OK = False Then
|
||
Logger.Warn("⚠ Error while IDBNewObjectData")
|
||
Logger.Error(oResult.ErrorMessage)
|
||
End If
|
||
|
||
Return oResult.OK
|
||
End Function
|
||
|
||
Private Function DeleteTermObjectFromMetadata(pObjectId As Long, pAttributeName As String, pTerm2Delete As String, Optional pUsername As String = "", Optional pLanguage As String = "") As Boolean
|
||
Try
|
||
Dim oLanguage = GetUserLanguage(pLanguage)
|
||
Dim oUsername = GetUserName(pUsername)
|
||
|
||
Dim oIdIsForeign As Integer = 1
|
||
Dim oDELSQL = $"EXEC PRIDB_DELETE_TERM_OBJECT_METADATA {pObjectId},'{pAttributeName}','{pTerm2Delete}','{oUsername}','{oLanguage}',{oIdIsForeign}"
|
||
Dim oResult = _Channel.ExecuteNonQuery_MSSQL_IDB(oDELSQL)
|
||
|
||
If oResult.OK = False Then
|
||
Logger.Warn("⚠ Error while deleting Term object")
|
||
Logger.Error(oResult.ErrorMessage)
|
||
End If
|
||
|
||
Return oResult.OK
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return False
|
||
End Try
|
||
End Function
|
||
|
||
#Region "GetDatatable"
|
||
Public Function GetDatatableFromIDB(pSQL As String) As GetDatatableResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.IDB
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDB))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDB))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Function GetDatatableFromECM(pSQL As String) As GetDatatableResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.ECM
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromECM))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromECM))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Function GetDatatableFromConnection(pSQL As String, pConnectionId As Integer) As GetDatatableResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ReturnDatatable(New GetDatatableRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.None,
|
||
.ConnectionId = pConnectionId
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnection))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnection))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetDatatableFromIDBAsync(pSQL As String) As Task(Of GetDatatableResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.IDB
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDBAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromIDBAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetDatatableFromECMAsync(pSQL As String) As Task(Of GetDatatableResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Logger.Debug("GetDatatableFromECMAsync will be called with SQL [{0}]", pSQL)
|
||
Return Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.ECM
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromECMAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromECMAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetDatatableFromConnectionAsync(pSQL As String, Optional pConnectionId As Integer = 0) As Task(Of GetDatatableResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ReturnDatatableAsync(New GetDatatableRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.None,
|
||
.ConnectionId = pConnectionId
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnectionAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetDatatableFromConnectionAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
#End Region
|
||
|
||
#Region "GetScalarValue"
|
||
Public Function GetScalarValueFromIDB(pSQL As String) As GetScalarValueResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.IDB
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDB))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDB))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Function GetScalarValueFromECM(pSQL As String) As GetScalarValueResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.ECM
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECM))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECM))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Function GetScalarValueFromConnection(pSQL As String, pConnectionId As Integer) As GetScalarValueResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ReturnScalarValue(New GetScalarValueRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.None,
|
||
.ConnectionId = pConnectionId
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnection))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnection))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetScalarValueFromIDBAsync(pSQL As String) As Task(Of GetScalarValueResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.IDB
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDBAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromIDBAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetScalarValueFromECMAsync(pSQL As String) As Task(Of GetScalarValueResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.ECM
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECMAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromECMAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetScalarValueFromConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of GetScalarValueResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.None,
|
||
.ConnectionId = pConnectionId
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnectionAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(GetScalarValueFromConnectionAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
#End Region
|
||
|
||
#Region "ExecuteNonQuery"
|
||
Public Function ExecuteNonQueryFromIDB(pSQL As String) As ExecuteNonQueryResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.IDB
|
||
})
|
||
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
|
||
End Try
|
||
End Function
|
||
|
||
Public Function ExecuteNonQueryFromECM(pSQL As String) As ExecuteNonQueryResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.ECM
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECM))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECM))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Function ExecuteNonQueryFromConnection(pSQL As String, pConnectionId As Integer) As ExecuteNonQueryResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.ExecuteNonQuery(New ExecuteNonQueryRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.None,
|
||
.ConnectionId = pConnectionId
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnection))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnection))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function ExecuteNonQueryFromIDBAsync(pSQL As String) As Task(Of ExecuteNonQueryResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.IDB
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromIDBAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromIDBAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function ExecuteNonQueryFromECMAsync(pSQL As String) As Task(Of ExecuteNonQueryResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.ECM
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECMAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromECMAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function ExecuteNonQueryFromConnectionAsync(pSQL As String, pConnectionId As Integer) As Task(Of ExecuteNonQueryResponse)
|
||
EnsureAvailable()
|
||
Try
|
||
Return Await _Channel.ExecuteNonQueryAsync(New ExecuteNonQueryRequest() With {
|
||
.SqlCommand = pSQL,
|
||
.NamedDatabase = DatabaseName.None,
|
||
.ConnectionId = pConnectionId
|
||
})
|
||
Catch ex As EndpointNotFoundException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnectionAsync))
|
||
Catch ex As CommunicationException
|
||
HandleCommunicationError(ex, NameOf(ExecuteNonQueryFromConnectionAsync))
|
||
Catch ex As Exception
|
||
Logger.Error(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
|
||
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
|
||
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
|
||
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
|
||
End Try
|
||
End Function
|
||
|
||
|
||
|
||
''' <summary>
|
||
''' Return infos about a file object
|
||
''' </summary>
|
||
''' <param name="UserId"></param>
|
||
''' <param name="ObjectId"></param>
|
||
''' <returns></returns>
|
||
Public Function GetDocumentInfo(UserId As Long, ObjectId As Long) As DocumentInfo
|
||
Try
|
||
Dim oResponse As DocumentInfoResponse = _Channel.GetFileInfoByObjectId(New DocumentInfoRequest With {
|
||
.ObjectId = ObjectId,
|
||
.UserId = UserId
|
||
})
|
||
|
||
Return New DocumentInfo With {
|
||
.AccessRight = oResponse.FileRight,
|
||
.FullPath = oResponse.FullPath
|
||
}
|
||
|
||
Catch ex As FaultException(Of ObjectDoesNotExistFault)
|
||
Logger.Error(ex)
|
||
Throw ex
|
||
|
||
Catch ex As FaultException
|
||
Logger.Error(ex)
|
||
Throw ex
|
||
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw ex
|
||
|
||
End Try
|
||
End Function
|
||
|
||
Public Async Function GetDocumentInfoAsync(UserId As Long, ObjectId As Long) As Task(Of DocumentInfo)
|
||
Try
|
||
Dim oParams = New DocumentInfoRequest With {
|
||
.ObjectId = ObjectId,
|
||
.UserId = UserId
|
||
}
|
||
Dim oResponse As DocumentInfoResponse = Await _Channel.GetFileInfoByObjectIdAsync(oParams)
|
||
|
||
Return New DocumentInfo With {
|
||
.AccessRight = oResponse.FileRight,
|
||
.FullPath = oResponse.FullPath
|
||
}
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Throw ex
|
||
End Try
|
||
End Function
|
||
''' <summary>
|
||
''' Returns a live monitoring snapshot from the service (active sessions, users)
|
||
''' </summary>
|
||
Public Function GetServiceStatus() As ServiceStatusResponse
|
||
EnsureAvailable()
|
||
Try
|
||
Return _Channel.GetServiceStatus()
|
||
Catch ex As Exception
|
||
Logger.Error(ex)
|
||
Return Nothing
|
||
End Try
|
||
End Function
|
||
|
||
#Region "Private Functions"
|
||
|
||
|
||
Private Function GetUserLanguage(pOverrideLanguage As String) As String
|
||
Return ObjectEx.NotNull(pOverrideLanguage, Threading.Thread.CurrentThread.CurrentUICulture.Name)
|
||
End Function
|
||
|
||
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"
|
||
Public Class StreamedFile
|
||
Public Stream As MemoryStream
|
||
Public FileName As String
|
||
End Class
|
||
|
||
Public Class FileList
|
||
Public Datatable As DataTable
|
||
End Class
|
||
|
||
Public Class DocumentInfo
|
||
Public Id As Long
|
||
Public FullPath As String
|
||
Public AccessRight As AccessRight
|
||
End Class
|
||
|
||
Public Class VariableValue
|
||
Public ReadOnly Property IsVector As Boolean = False
|
||
|
||
Public Property Value As Object
|
||
Public Property Type As Type
|
||
|
||
Public Sub New()
|
||
MyClass.New(Nothing)
|
||
End Sub
|
||
|
||
Public Sub New(pValue As Object)
|
||
' Check if value is a collection
|
||
If TypeOf pValue Is IEnumerable Then
|
||
IsVector = True
|
||
End If
|
||
|
||
' Try to determine the type
|
||
If IsNothing(pValue) Then
|
||
Type = Nothing
|
||
Else
|
||
Type = pValue.GetType
|
||
End If
|
||
|
||
Value = pValue
|
||
End Sub
|
||
End Class
|
||
|
||
|
||
#End Region
|
||
|
||
Public Class ObjectAttribute
|
||
Public Property Id As Long
|
||
Public Property Title As String
|
||
Public Property Type As String
|
||
|
||
Public Property ValueBigInt As Long
|
||
Public Property ValueText As String
|
||
Public Property ValueDecimal As Decimal
|
||
Public Property ValueDate As DateTime
|
||
|
||
Public ReadOnly Property Value As Object
|
||
Get
|
||
Return GetValue()
|
||
End Get
|
||
End Property
|
||
|
||
Private Function GetValue() As Object
|
||
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
|
||
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 ' ← ClientStatus endet hier – kein GetServiceStatus mehr drin
|
||
|
||
End Class
|