6 Commits

Author SHA1 Message Date
Jonathan Jenne
f6fc3be8ed ZUGFeRDService: Integrate MSSQL Transactions, Rollback for Application Exceptions #MR-2 2021-04-15 15:57:09 +02:00
Jonathan Jenne
07ce5488df EDMIService: Remove Calls to UpdateTraceLogging 2021-04-15 15:52:17 +02:00
Jonathan Jenne
673e8b83c5 Database: Version 2.0.2 2021-04-15 15:51:46 +02:00
Jonathan Jenne
a45b8db100 Database: Remove TestCanConnect for most functions, check connection state for TestCanConnect, check for empty connection string in maskconnectionstring 2021-04-15 15:50:25 +02:00
Jonathan Jenne
d17ef894a0 Database: Version 2.0.1 2021-04-15 13:31:44 +02:00
Jonathan Jenne
7e2359f006 Database: Expose GetConnection function 2021-04-15 13:31:35 +02:00
5 changed files with 100 additions and 71 deletions

View File

@@ -63,6 +63,18 @@ Public Class MSSQLServer
Return oConnectionStringBuilder.ToString
End Function
Public Function GetConnection() As SqlConnection
Try
Dim oConnection = GetSQLConnection()
oConnection.Open()
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 Mode = TransactionMode.NoTransaction Then
Return Nothing
@@ -156,7 +168,11 @@ Public Class MSSQLServer
End If
_Logger.Debug("Testing connection to [{0}]", MaskConnectionString(Connection.ConnectionString))
Connection.Open()
If Connection.State = ConnectionState.Closed Then
Connection.Open()
End If
Connection.Close()
Return True
Catch ex As Exception
@@ -187,6 +203,10 @@ Public Class MSSQLServer
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
@@ -217,7 +237,6 @@ Public Class MSSQLServer
End Using
End Function
Public Async Function GetDatatableAsync(SqlCommand As String) As Task(Of DataTable)
Return Await Task.Run(Function() GetDatatable(SqlCommand, _Timeout))
End Function
@@ -232,10 +251,6 @@ Public Class MSSQLServer
Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As DataTable
If TestCanConnect(SqlConnection) = False Then
Return Nothing
End If
Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Dim oTable As New DataTable() With {.TableName = TABLE_DEFAULT}
@@ -250,8 +265,6 @@ Public Class MSSQLServer
_Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand)
oAdapter.Fill(oTable)
_Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand)
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand)
@@ -296,10 +309,6 @@ Public Class MSSQLServer
Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As Boolean
If TestCanConnect(SqlConnection) = False Then
Return False
End If
Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Try
@@ -353,9 +362,6 @@ Public Class MSSQLServer
Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As Object
If TestCanConnect() = False Then
Return Nothing
End If
Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Dim oResult As Object = Nothing
@@ -421,10 +427,6 @@ Public Class MSSQLServer
''' <param name="commandtimeout">Optional Timeout</param>
''' <remarks></remarks>
Public Sub NewExecuteNonQueryAsync(SqlCommand As String, Optional commandtimeout As Integer = 120)
If TestCanConnect() = False Then
Exit Sub
End If
_Logger.Debug("NewExecuteNonQueryAsync: Running Query [{0}]", SqlCommand)
Try

View File

@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2.0.0.0")>
<Assembly: AssemblyFileVersion("2.0.0.0")>
<Assembly: AssemblyVersion("2.0.2.0")>
<Assembly: AssemblyFileVersion("2.0.2.0")>

View File

@@ -2,6 +2,7 @@
Imports DigitalData.Modules.Database
Imports System.Data
Imports System.IO
Imports System.Data.SqlClient
Public Class EmailFunctions
Private ReadOnly _logConfig As LogConfig
@@ -62,7 +63,7 @@ Public Class EmailFunctions
_logger.Error(ex)
End Try
End Sub
Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer)
Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer, Transaction As SqlTransaction)
If pEmailData Is Nothing Then
_logger.Warn("EmailData is empty. Email will not be sent!")
Exit Sub
@@ -97,7 +98,7 @@ Public Class EmailFunctions
_logger.Debug("Subject: {0}", oSubject)
_logger.Debug("Body {0}", oFinalBodyText)
Dim osql = $"Select MAX(GUID) FROM TBEMLP_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
Dim oHistoryID = _mssql.GetScalarValue(osql)
Dim oHistoryID = _mssql.GetScalarValue(osql, Transaction)
'osql = $"select * from TBEMLP_EMAIL_OUT where REFERENCE_ID = {oHistoryID} and EMAIL_ADRESS = '{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
@@ -128,7 +129,7 @@ Public Class EmailFunctions
,'{SourceProcedure}'
,'{oCreatedWho}'
,'{oAttachment}')"
_mssql.ExecuteNonQuery(oInsert)
_mssql.ExecuteNonQuery(oInsert, Transaction)
Else
'If oDTResult.Rows.Count = 0 Then
' _logger.Debug("Email has already been sent!!")
@@ -173,7 +174,7 @@ Public Class EmailFunctions
Dim oAttachmentFile = MessageId & ".eml"
Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
If IO.File.Exists(oAttachmentPath) Then
If File.Exists(oAttachmentPath) Then
Return oAttachmentPath
Else
_logger.Warn("Email File {0} does not exist. Empty String will be returned.", oAttachmentPath)

View File

@@ -2,18 +2,14 @@
Imports System.Data
Imports System.IO
Imports System.Linq
Imports System.Reflection
Imports System.Security.Cryptography
Imports System.Text.RegularExpressions
Imports System.Xml
Imports DigitalData.Modules.Filesystem
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Jobs.Exceptions
Imports DigitalData.Modules.Logging
Imports FirebirdSql.Data.FirebirdClient
Imports GdPicture14
Imports System.Data.SqlClient
Public Class ImportZUGFeRDFiles
Implements IJob
@@ -111,11 +107,11 @@ Public Class ImportZUGFeRDFiles
Return oEmailData
End Function
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String)
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String, Transaction As SqlTransaction)
Try
'PRCUST_ADD_HISTORY_STATE: @MessageID VARCHAR(250), @TITLE1 VARCHAR(250), @TITLE2 VARCHAR(250)
Dim oSQL = $"EXEC PRCUST_ADD_HISTORY_STATE '{oMessageID}','{oTitle}','{oTitle1}','{oComment.Replace("'", "''")}'"
_mssql.ExecuteNonQuery(oSQL)
_mssql.ExecuteNonQuery(oSQL, Transaction)
Catch ex As Exception
_logger.Error(ex)
End Try
@@ -159,12 +155,18 @@ Public Class ImportZUGFeRDFiles
For Each oFileGroup In oGrouped
' Start a new transaction for each file group.
' This way we can rollback database changes for the whole filegroup in case something goes wrong.
Dim oConnection As FbConnection = _firebird.GetConnection()
Dim oTransaction As FbTransaction = oConnection.BeginTransaction()
Dim oFBConnection As FbConnection = _firebird.GetConnection()
Dim oFBTransaction As FbTransaction = oFBConnection.BeginTransaction()
Dim oSQLConnection As SqlConnection = _mssql.GetConnection()
Dim oSQLTransaction As SqlTransaction = oSQLConnection.BeginTransaction()
' Count the amount of ZUGFeRD files
Dim oZUGFeRDCount As Integer = 0
' Set the default Move Directory
Dim oMoveDirectory As String = oArgs.ErrorDirectory
' Flag to save if the whole process was a success.
' Will be set only at the end of the function if no error occurred.
Dim oIsSuccess As Boolean = False
@@ -275,10 +277,9 @@ Public Class ImportZUGFeRDFiles
Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{oMessageId}'"
Dim oStep As String
oStep = "Firebird TBEDMI_ITEM_VALUE Delete messageID Items"
Try
_firebird.ExecuteNonQueryWithConnection(oDelSQL, oConnection, Firebird.TransactionMode.ExternalTransaction, oTransaction)
_firebird.ExecuteNonQueryWithConnection(oDelSQL, oFBConnection)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
@@ -287,7 +288,7 @@ Public Class ImportZUGFeRDFiles
If oArgs.InsertIntoSQLServer = True Then
oStep = "MSSQL TBEDMI_ITEM_VALUE Delete messageID Items"
Try
_mssql.ExecuteNonQuery(oDelSQL)
_mssql.ExecuteNonQueryWithConnectionObject(oDelSQL, oSQLConnection)
Catch ex As Exception
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
End Try
@@ -307,13 +308,13 @@ Public Class ImportZUGFeRDFiles
_logger.Debug("Mapping Property [{0}] with value [{1}], Will be inserted into table [{2}]", oProperty.TableColumn, oProperty.Value.Replace("'", "''"), oProperty.TableName)
' Insert into SQL Server
If oArgs.InsertIntoSQLServer = True Then
Dim oResult = _mssql.ExecuteNonQuery(oCommand)
Dim oResult = _mssql.ExecuteNonQueryWithConnectionObject(oCommand, oSQLConnection, MSSQLServer.TransactionMode.ExternalTransaction, oSQLTransaction)
If oResult = False Then
_logger.Warn($"SQL Command [{oCommand}] was not successful. Check the log.")
End If
End If
' Insert into Firebird
_firebird.ExecuteNonQueryWithConnection(oCommand, oConnection, Firebird.TransactionMode.ExternalTransaction, oTransaction)
_firebird.ExecuteNonQueryWithConnection(oCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
Next
Next
@@ -326,9 +327,11 @@ Public Class ImportZUGFeRDFiles
'Log the History
If oMD5CheckSum <> String.Empty Then
Dim oInsertCommand = $"INSERT INTO TBEDM_ZUGFERD_HISTORY_IN (MESSAGE_ID, MD5HASH) VALUES ('{oMessageId}', '{oMD5CheckSum}')"
_firebird.ExecuteNonQueryWithConnection(oInsertCommand, oConnection, Firebird.TransactionMode.ExternalTransaction, oTransaction)
'commit the transaction
oTransaction.Commit()
_firebird.ExecuteNonQueryWithConnection(oInsertCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
' History ID is only need in case of an error
oFBTransaction.Commit()
Try
Dim oSQL = $"SELECT MAX(GUID) FROM TBEDM_ZUGFERD_HISTORY_IN WHERE MESSAGE_ID = '{oMessageId}'"
HISTORY_ID = _firebird.GetScalarValue(oSQL)
@@ -342,55 +345,55 @@ Public Class ImportZUGFeRDFiles
Catch ex As MD5HashException
_logger.Error(ex)
oTransaction.Rollback()
'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Already processed (MD5Hash)' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_MD5_ERROR
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId)
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "")
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction)
Catch ex As InvalidFerdException
_logger.Error(ex)
oTransaction.Rollback()
'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - ZUGFeRD yes but incorrect format' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_INVALID_DOCUMENT
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId)
AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "")
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "", oSQLTransaction)
Catch ex As TooMuchFerdsException
_logger.Error(ex)
oTransaction.Rollback()
'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - More than one ZUGFeRD-document in email' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_TOO_MUCH_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId)
AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "")
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "", oSQLTransaction)
Catch ex As NoFerdsException
_logger.Error(ex)
oTransaction.Rollback()
'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - no ZUGFeRD-Document in email' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_NO_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId)
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "")
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "", oSQLTransaction)
Catch ex As MissingValueException
_logger.Error(ex)
oTransaction.Rollback()
'oFBTransaction.Rollback()
Dim oMessage As String = ""
For Each prop In oMissingProperties
@@ -401,33 +404,56 @@ Public Class ImportZUGFeRDFiles
Dim oBody = CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId)
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage, oSQLTransaction)
Catch ex As OutOfMemoryException
_logger.Warn("OutOfMemory Error occurred: {0}", ex.Message)
_logger.Error(ex)
oTransaction.Rollback()
' Rollback Firebird
oFBTransaction.Rollback()
' Rollback MSSQL
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
'Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Out of memory' WHERE GUID = '{HISTORY_ID}'"
'_firebird.ExecuteNonQuery(oSQL)
'AddRejectedState(oMessageId, "OutOfMemoryException", "", ex.Message)
Catch ex As Exception
_logger.Warn("Unknown Error occurred: {0}", ex.Message)
_logger.Error(ex)
oTransaction.Rollback()
' Rollback Firebird
oFBTransaction.Rollback()
' Rollback MSSQL
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
'Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Unknown error occured' WHERE GUID = '{HISTORY_ID}'"
'_firebird.ExecuteNonQuery(oSQL)
'oMoveDirectory = oArgs.ErrorDirectory
'AddRejectedState(oMessageId, "UnexpectedException", "", ex.Message)
Finally
oConnection.Close()
Try
' If everything went OK, finally commit all changes to the Database
' ==================================================================
If oIsSuccess Then
' Commit SQL Transaction
oSQLTransaction.Commit()
' Commit Firebird Transaction
oFBTransaction.Commit()
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Transactions were not committed successfully.")
End Try
Try
oFBConnection.Close()
oSQLConnection.Close()
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Connections were not closed successfully.")
End Try
Try
' If an application error occurred, dont move files so they will be processed again later

View File

@@ -52,7 +52,7 @@ Public Class WindowsService
End If
Next
Catch ex As Exception
_Logger.Error(ex)
End Try
_Logger.Info("Service {0} is starting...", SERVICE_DISPLAY_NAME)
@@ -63,7 +63,7 @@ Public Class WindowsService
_Config = _ConfigManager.Config
_LogConfig.Debug = _ConfigManager.Config.Debug
UpdateTraceLogging()
'UpdateTraceLogging()
Dim oTimer As New Timers.Timer(60000)
AddHandler oTimer.Elapsed, Sub()
@@ -72,7 +72,7 @@ Public Class WindowsService
_Config = _ConfigManager.Config
_LogConfig.Debug = _ConfigManager.Config.Debug
UpdateTraceLogging()
'UpdateTraceLogging()
End Sub
oTimer.Start()