Imports System.ComponentModel Imports System.Data.Common Imports System.Data.SqlClient Imports DigitalData.Modules.Encryption Imports DigitalData.Modules.Logging Public Class MSSQLServer Implements IDatabase Public DBInitialized As Boolean = False Public CurrentSQLConnectionString As String = "" Public Const TIMEOUT_DEFAULT As Integer = 120 Public Const TABLE_DEFAULT As String = "DDRESULT" Private ReadOnly _Timeout As Integer Private ReadOnly _Logger As Logger Public Enum TransactionMode NoTransaction ExternalTransaction WithTransaction End Enum Public Sub New(LogConfig As LogConfig, ConnectionString As String, Optional Timeout As Integer = 120) _Logger = LogConfig.GetLogger() _Timeout = Timeout CurrentSQLConnectionString = ConnectionString Try DBInitialized = TestCanConnect() Catch ex As Exception DBInitialized = False _Logger.Error(ex) End Try End Sub Public Sub New(LogConfig As LogConfig, Server As String, Database As String, UserId As String, Password As String, Optional Timeout As Integer = 120) _Logger = LogConfig.GetLogger() _Timeout = Timeout CurrentSQLConnectionString = GetConnectionString(Server, Database, UserId, Password) Try DBInitialized = TestCanConnect() Catch ex As Exception DBInitialized = False _Logger.Error(ex) End Try End Sub ''' ''' Encrypts a connection string password. ''' ''' A connection string with a plain-text password ''' The connection string with the password encrypted. Public Shared Function EncryptConnectionString(ConnectionString As String) As String Dim oEncryption As New EncryptionLegacy() Dim oBuilder As New SqlConnectionStringBuilder() With {.ConnectionString = ConnectionString} Dim oEncryptedPassword = oEncryption.EncryptData(oBuilder.Password) oBuilder.Password = oEncryptedPassword Return oBuilder.ToString() End Function ''' ''' Decrypts a connection string password. ''' ''' A connection string with a encrypted password ''' The connection string with the password decrypted. Public Shared Function DecryptConnectionString(ConnectionString As String) As String Dim oEncryption As New EncryptionLegacy() Dim oBuilder As New SqlConnectionStringBuilder() With {.ConnectionString = ConnectionString} Dim oDecryptedPassword = oEncryption.DecryptData(oBuilder.Password) oBuilder.Password = oDecryptedPassword Return oBuilder.ToString() End Function Public Function GetConnectionString(Server As String, Database As String, UserId As String, Password As String) As String Dim oConnectionStringBuilder As New SqlConnectionStringBuilder() With { .DataSource = Server, .InitialCatalog = Database, .UserID = UserId, .Password = Password } Return oConnectionStringBuilder.ToString End Function Public Function GetConnection() As SqlConnection Try Dim oConnection = GetSQLConnection() Return oConnection Catch ex As Exception _Logger.Error(ex) Return Nothing End Try End Function Private Function MaybeGetTransaction(Connection As SqlConnection, Mode As TransactionMode, Transaction As SqlTransaction) As SqlTransaction If Connection Is Nothing Then Throw New ArgumentNullException("Connection") End If If Mode = TransactionMode.NoTransaction Then Return Nothing ElseIf Mode = TransactionMode.ExternalTransaction Then Return Transaction Else Return Connection.BeginTransaction() End If End Function Private Function MaybeCommitTransaction(Transaction As SqlTransaction, TransactionMode As TransactionMode) As Boolean Select Case TransactionMode Case TransactionMode.NoTransaction Return True Case TransactionMode.ExternalTransaction Return True Case TransactionMode.WithTransaction Try Transaction.Commit() Return True Catch ex As Exception _Logger.Error(ex) Return False End Try Case Else Return True End Select End Function Public Function Get_ConnectionStringforID(pConnectionId As Integer) Dim connectionString As String = "" Try Dim oDTConnection As DataTable = GetDatatable($"SELECT * FROM TBDD_CONNECTION WHERE GUID = {pConnectionId}") If oDTConnection.Rows.Count = 1 Then Dim oRow As DataRow = oDTConnection.Rows(0) Dim oProvider = oRow.Item("SQL_PROVIDER").ToString.ToUpper Dim oServer = oRow.Item("SERVER") Dim oDatabase = oRow.Item("DATENBANK") Dim oUser = oRow.Item("USERNAME") Dim oPassword = oRow.Item("PASSWORD") Select Case oProvider Case "MS-SQL" If oUser = "WINAUTH" Then connectionString = $"Server={oServer};Database={oDatabase};Trusted_Connection=True;" Else connectionString = $"Server={oServer};Database={oDatabase};User Id={oUser};Password={oPassword};" End If Case "Oracle" If oRow.Item("BEMERKUNG").ToString.Contains("without tnsnames") Then connectionString = $"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={oServer})(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME={oDatabase})));User Id={oUser};Password={oPassword};" Else connectionString = $"Data Source={oServer};Persist Security Info=True;User Id={oUser};Password={oPassword};Unicode=True" End If Case Else _Logger.Warn("Provider {0} nicht unterstützt!", oProvider) End Select Else _Logger.Info("No entry for Connection-ID: " & pConnectionId.ToString) End If Catch ex As Exception _Logger.Error(ex) _Logger.Info("Error in bei Get_ConnectionStringforID") End Try Return connectionString End Function ' Private Function TestCanConnect() As Boolean Return TestCanConnect(CurrentSQLConnectionString) End Function ' Private Function TestCanConnect(ConnectionString As String) As Boolean Try _Logger.Debug("Testing connection to [{0}]", MaskConnectionString(ConnectionString)) Dim oDecryptedConnectionString = DecryptConnectionString(ConnectionString) Dim oConnection As New SqlConnection(oDecryptedConnectionString) OpenSQLConnection(oConnection) oConnection.Close() Return True Catch ex As Exception _Logger.Error(ex) Return False End Try End Function ' Private Function TestCanConnect(Connection As SqlConnection) As Boolean Try If Connection Is Nothing Then _Logger.Warn("TestCanConnect: Connection is nothing!") Return False End If _Logger.Debug("Testing connection to [{0}]", MaskConnectionString(Connection.ConnectionString)) OpenSQLConnection(Connection) Connection.Close() Return True Catch ex As Exception _Logger.Error(ex) Return False End Try End Function ''' ''' This Function intentionally has no try..catch block to have any errors caught outside ''' ''' ''' ' Private Function OpenSQLConnection(Connection As SqlConnection) As SqlConnection If Connection.State = ConnectionState.Closed Then Connection.Open() End If Return Connection End Function ' Private Function GetSQLConnection() As SqlConnection Return GetConnection(CurrentSQLConnectionString) End Function ' Private Function GetConnection(ConnectionString As String) As SqlConnection Try Dim oConnection As New SqlConnection(ConnectionString) oConnection = OpenSQLConnection(oConnection) Dim oMaskedConnectionString = MaskConnectionString(ConnectionString) _Logger.Debug("The Following Connection is open: {0}", oMaskedConnectionString) Return oConnection Catch ex As Exception _Logger.Error(ex) Return Nothing End Try End Function Private Function MaskConnectionString(ConnectionString As String) As String Try If ConnectionString Is Nothing OrElse ConnectionString.Length = 0 Then Throw New ArgumentNullException("ConnectionString") End If Dim oBuilder As New SqlConnectionStringBuilder() With {.ConnectionString = ConnectionString} Dim oConnectionString = ConnectionString.Replace(oBuilder.Password, "XXXXX") Return oConnectionString Catch ex As Exception _Logger.Error(ex) Return "Invalid ConnectionString" End Try End Function ' Public Function GetDatatable(SqlCommand As String) As DataTable Implements IDatabase.GetDatatable Return GetDatatable(SqlCommand, _Timeout) End Function ''' ''' Returns a datatable for a sql-statement ''' ''' sqlcommand for datatable (select XYZ from TableORView) ''' Returns a datatable ' Public Function GetDatatable(SqlCommand As String, Timeout As Integer) As DataTable Implements IDatabase.GetDatatable Using oSqlConnection = GetSQLConnection() Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.WithTransaction, Nothing, Timeout) End Using End Function ' Public Function GetDatatable(SqlCommand As String, Transaction As SqlTransaction, Optional Timeout As Integer = 120) As DataTable Using oSqlConnection = GetSQLConnection() Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.ExternalTransaction, Transaction, Timeout) End Using End Function ' Public Async Function GetDatatableAsync(SqlCommand As String, Optional Timeout As Integer = 120) As Task(Of DataTable) Return Await Task.Run(Function() GetDatatable(SqlCommand, Timeout)) End Function ' Public Function GetDatatableWithConnection(SqlCommand As String, ConnectionString As String, Optional Timeout As Integer = 120) As DataTable Using oConnection = GetConnection(ConnectionString) Return GetDatatableWithConnectionObject(SqlCommand, oConnection, Timeout:=Timeout) End Using End Function ' Public Function GetDatatableWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection, Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction, Optional Transaction As SqlTransaction = Nothing, Optional Timeout As Integer = 120) As DataTable Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction) Dim oTable As New DataTable() With {.TableName = TABLE_DEFAULT} Try Dim oAdapter As New SqlDataAdapter(New SqlCommand With { .CommandText = SqlCommand, .Connection = SqlConnection, .Transaction = oTransaction, .CommandTimeout = Timeout }) _Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand) oAdapter.Fill(oTable) Catch ex As Exception _Logger.Error(ex) _Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand) Throw ex Finally MaybeCommitTransaction(oTransaction, TransactionMode) End Try Return oTable End Function ' Public Function ExecuteNonQuery(SQLCommand As String) As Boolean Implements IDatabase.ExecuteNonQuery Using oConnection = GetSQLConnection() Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, _Timeout) End Using End Function Public Function ExecuteNonQuery(SQLCommand As String, Timeout As Integer) As Boolean Implements IDatabase.ExecuteNonQuery Using oConnection = GetSQLConnection() Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) End Using End Function Public Function ExecuteNonQuery(SQLCommand As String, Transaction As SqlTransaction, Optional Timeout As Integer = 120) As Boolean Using oConnection = GetSQLConnection() Return ExecuteNonQueryWithConnectionObject(SQLCommand, Transaction.Connection, TransactionMode.ExternalTransaction, Transaction, Timeout) End Using End Function Public Async Function ExecuteNonQueryAsync(SQLCommand As String, Optional Timeout As Integer = 120) As Task(Of Boolean) Return Await Task.Run(Function() ExecuteNonQuery(SQLCommand, Timeout)) End Function Public Function ExecuteNonQueryWithConnection(pSQLCommand As String, ConnString As String, Optional Timeout As Integer = 120) As Boolean Using oConnection = GetConnection(ConnString) Return ExecuteNonQueryWithConnectionObject(pSQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) End Using End Function ' Public Function ExecuteNonQueryWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection, Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction, Optional Transaction As SqlTransaction = Nothing, Optional Timeout As Integer = 120) As Boolean Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction) Try Using oSQLCOmmand = SqlConnection.CreateCommand() oSQLCOmmand.CommandText = SqlCommand oSQLCOmmand.CommandTimeout = Timeout oSQLCOmmand.Transaction = oTransaction oSQLCOmmand.ExecuteNonQuery() End Using Return True Catch ex As Exception _Logger.Error(ex) _Logger.Warn("ExecuteNonQueryWithConnectionObject: Error in ExecuteNonQueryWithConnectionObject while executing command: [{0}]-[{1}]", SqlCommand, SqlConnection.ConnectionString) Return False Finally MaybeCommitTransaction(oTransaction, TransactionMode) End Try End Function Public Function GetScalarValue(SQLQuery As String) As Object Implements IDatabase.GetScalarValue Using oConnection As SqlConnection = GetSQLConnection() Return GetScalarValueWithConnectionObject(SQLQuery, oConnection) End Using End Function Public Function GetScalarValue(SQLCommand As String, Timeout As Integer) As Object Implements IDatabase.GetScalarValue Using oConnection = GetSQLConnection() Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) End Using End Function Public Function GetScalarValue(SQLCommand As String, Transaction As SqlTransaction, Optional Timeout As Integer = 120) As Object Using oConnection = GetSQLConnection() Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.ExternalTransaction, Transaction, Timeout) End Using End Function Public Async Function GetScalarValueAsync(SQLQuery As String, Optional Timeout As Integer = 120) As Task(Of Object) Return Await Task.Run(Function() GetScalarValue(SQLQuery, Timeout)) End Function Public Function GetScalarValueWithConnection(SQLCommand As String, ConnectionString As String, Optional Timeout As Integer = 120) As Object Using oConnection = GetConnection(ConnectionString) Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) End Using End Function Public Function GetScalarValueWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection, Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction, Optional Transaction As SqlTransaction = Nothing, Optional Timeout As Integer = 120) As Object Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction) Dim oResult As Object = Nothing Try Using oSQLCOmmand = SqlConnection.CreateCommand() oSQLCOmmand.CommandText = SqlCommand oSQLCOmmand.CommandTimeout = Timeout oSQLCOmmand.Transaction = oTransaction oResult = oSQLCOmmand.ExecuteScalar() End Using Catch ex As Exception _Logger.Error(ex) _Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand) Finally MaybeCommitTransaction(oTransaction, TransactionMode) End Try Return oResult End Function Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String, Timeout As Integer) As Object Try If TestCanConnect() = False Then Return Nothing End If _Logger.Debug("GetScalarValue: Running Query [{0}]", SQLCommand) If SQLCommand.CommandText.Contains(" ") Then SQLCommand.CommandType = CommandType.Text Else SQLCommand.CommandType = CommandType.StoredProcedure End If Using oConnection As SqlConnection = GetSQLConnection() SQLCommand.Connection = oConnection SQLCommand.Parameters(OutputParameter).Direction = ParameterDirection.Output SQLCommand.CommandTimeout = Timeout SQLCommand.ExecuteNonQuery() oConnection.Close() Return SQLCommand.Parameters(OutputParameter).Value End Using Catch ex As Exception _Logger.Error(ex) _Logger.Warn($"GetScalarValue failed SQLCommand [{SQLCommand}]") Return Nothing End Try End Function Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String) As Object Return GetScalarValue(SQLCommand, OutputParameter, _Timeout) End Function ''' ''' Executes the passed sql-statement in asyncmode ''' ''' the sql statement ''' Optional Timeout ''' Public Sub NewExecuteNonQueryAsync(SqlCommand As String, Optional commandtimeout As Integer = 120) _Logger.Debug("NewExecuteNonQueryAsync: Running Query [{0}]", SqlCommand) Try Dim oCallback As New AsyncCallback(AddressOf NewExecuteNonQueryAsync_Callback) Using oConnection As SqlConnection = GetSQLConnection() Using oSQLCOmmand = oConnection.CreateCommand() oSQLCOmmand.CommandText = SqlCommand oSQLCOmmand.CommandTimeout = commandtimeout oSQLCOmmand.BeginExecuteNonQuery(oCallback, oSQLCOmmand) End Using End Using Catch ex As Exception _Logger.Error(ex) _Logger.Warn($"NewExecuteNonQueryAsync failed SQLCommand [{SqlCommand}]") End Try End Sub Private Sub NewExecuteNonQueryAsync_Callback(ByVal result As IAsyncResult) Dim command As SqlCommand = CType(result.AsyncState, SqlCommand) Dim res = command.EndExecuteNonQuery(result) _Logger.Info("Finished executing Async database operation: {0}", command.CommandText) End Sub End Class