diff --git a/Database.Test/Database.Test.vbproj b/Database.Test/Database.Test.vbproj new file mode 100644 index 00000000..97982eb6 --- /dev/null +++ b/Database.Test/Database.Test.vbproj @@ -0,0 +1,17 @@ + + + + Database.Test + net6.0 + + false + + + + + + + + + + diff --git a/Database.Test/UnitTest1.vb b/Database.Test/UnitTest1.vb new file mode 100644 index 00000000..1e62d338 --- /dev/null +++ b/Database.Test/UnitTest1.vb @@ -0,0 +1,12 @@ +Imports Microsoft.VisualStudio.TestTools.UnitTesting + +Namespace Database.Test + + Public Class UnitTest1 + + Sub TestSub() + + End Sub + End Class +End Namespace + diff --git a/Database/Adapters/MSSQLServer.vb b/Database/Adapters/MSSQLServer.vb index 604febc9..8931c3ae 100644 --- a/Database/Adapters/MSSQLServer.vb +++ b/Database/Adapters/MSSQLServer.vb @@ -4,6 +4,7 @@ Imports System.Data.SqlClient Imports DigitalData.Modules.Encryption Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Base +Imports System.Threading Public Class MSSQLServer Implements IDatabase @@ -264,118 +265,174 @@ Public Class MSSQLServer End Try End Function - ' - Public Function GetDatatable(SqlCommand As String) As DataTable Implements IDatabase.GetDatatable - Return GetDatatable(SqlCommand, QueryTimeout) + ''' + ''' Returns a Datatable for a SQL Statement + ''' + ''' SQL Command Text for Datatable (select XYZ from TableORView) + ''' A datatable + Public Function GetDatatable(pSqlCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable Implements IDatabase.GetDatatable + Using oSqlConnection = GetSQLConnection() + Return GetDatatableWithConnectionObject(pSqlCommand, oSqlConnection, TransactionMode.WithTransaction, Nothing, pTimeout) + End Using End Function ''' - ''' Returns a datatable for a sql-statement + ''' 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 + ''' SQL Command Object for Datatable (select XYZ from TableORView) + ''' A datatable + Public Function GetDatatable(pSqlCommandObject As SqlCommand, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable Implements IDatabase.GetDatatable Using oSqlConnection = GetSQLConnection() - Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.WithTransaction, Nothing, Timeout) + Return GetDatatableWithConnectionObject(pSqlCommandObject, oSqlConnection, TransactionMode.WithTransaction, Nothing, pTimeout) End Using End Function - ' - Public Function GetDatatable(SqlCommand As String, Transaction As SqlTransaction, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Public Function GetDatatable(pSqlCommand As String, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable Using oSqlConnection = GetSQLConnection() - Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.ExternalTransaction, Transaction, Timeout) + Return GetDatatableWithConnectionObject(pSqlCommand, oSqlConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout) End Using End Function - ' - Public Async Function GetDatatableAsync(SqlCommand As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of DataTable) - Return Await Task.Run(Function() GetDatatable(SqlCommand, Timeout)) + Public Function GetDatatable(pSqlCommandObject As SqlCommand, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Using oSqlConnection = GetSQLConnection() + Return GetDatatableWithConnectionObject(pSqlCommandObject, oSqlConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout) + End Using End Function - ' - Public Function GetDatatableWithConnection(SqlCommand As String, pConnectionString As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Public Async Function GetDatatableAsync(pSqlCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of DataTable) + Return Await Task.Run(Function() GetDatatable(pSqlCommand, pTimeout)) + End Function + + Public Async Function GetDatatableAsync(pSqlCommandObject As SqlCommand, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of DataTable) + Return Await Task.Run(Function() GetDatatable(pSqlCommandObject, pTimeout)) + End Function + + Public Function GetDatatableWithConnection(pSqlCommand As String, pConnectionString As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable Using oConnection = GetConnection(pConnectionString) - Return GetDatatableWithConnectionObject(SqlCommand, oConnection, Timeout:=Timeout) + Return GetDatatableWithConnectionObject(pSqlCommand, oConnection, pTimeout:=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 = Constants.DEFAULT_TIMEOUT) As DataTable - Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction) + Public Function GetDatatableWithConnection(pSqlCommandObject As SqlCommand, pConnectionString As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Using oConnection = GetConnection(pConnectionString) + Return GetDatatableWithConnectionObject(pSqlCommandObject, oConnection, pTimeout:=Timeout) + End Using + End Function + + Public Function GetDatatableWithConnectionObject(pSqlCommand As String, pSqlConnection As SqlConnection, + Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction, + Optional pTransaction As SqlTransaction = Nothing, + Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Dim oSQLCommand As New SqlCommand(pSqlCommand) + Return GetDatatableWithConnectionObject(oSQLCommand, pSqlConnection, pTransactionMode, pTransaction, pTimeout) + End Function + + Public Function GetDatatableWithConnectionObject(pSqlCommandObject As SqlCommand, pSqlConnection As SqlConnection, + Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction, + Optional pTransaction As SqlTransaction = Nothing, + Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Dim oTransaction As SqlTransaction = MaybeGetTransaction(pSqlConnection, pTransactionMode, pTransaction) Dim oTable As New DataTable() With {.TableName = Constants.DEFAULT_TABLE} Try - Dim oAdapter As New SqlDataAdapter(New SqlCommand With { - .CommandText = SqlCommand, - .Connection = SqlConnection, - .Transaction = oTransaction, - .CommandTimeout = Timeout - }) + pSqlCommandObject.Connection = pSqlConnection + pSqlCommandObject.Transaction = oTransaction + pSqlCommandObject.CommandTimeout = pTimeout - Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand) + Using oAdapter As New SqlDataAdapter(pSqlCommandObject) + Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", pSqlCommandObject.CommandText) + oAdapter.Fill(oTable) + End Using - oAdapter.Fill(oTable) Catch ex As Exception Logger.Error(ex) - Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand) + Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", pSqlCommandObject) Throw ex Finally - MaybeCommitTransaction(oTransaction, TransactionMode) + MaybeCommitTransaction(oTransaction, pTransactionMode) End Try Return oTable End Function - ' - Public Function ExecuteNonQuery(SQLCommand As String) As Boolean Implements IDatabase.ExecuteNonQuery + Public Function ExecuteNonQuery(pSQLCommand As String) As Boolean Implements IDatabase.ExecuteNonQuery Using oConnection = GetSQLConnection() - Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, QueryTimeout) + Return ExecuteNonQueryWithConnectionObject(pSQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, QueryTimeout) End Using End Function - ' - Public Function ExecuteNonQuery(SQLCommand As String, Timeout As Integer) As Boolean Implements IDatabase.ExecuteNonQuery + Public Function ExecuteNonQuery(pSQLCommandObject As SqlCommand) As Boolean Using oConnection = GetSQLConnection() - Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) + Return ExecuteNonQueryWithConnectionObject(pSQLCommandObject, oConnection, TransactionMode.WithTransaction, Nothing, QueryTimeout) End Using End Function - ' - Public Function ExecuteNonQuery(SQLCommand As String, Transaction As SqlTransaction, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean + Public Function ExecuteNonQuery(pSQLCommand As String, pTimeout As Integer) As Boolean Implements IDatabase.ExecuteNonQuery Using oConnection = GetSQLConnection() - Return ExecuteNonQueryWithConnectionObject(SQLCommand, Transaction.Connection, TransactionMode.ExternalTransaction, Transaction, Timeout) + Return ExecuteNonQueryWithConnectionObject(pSQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, pTimeout) End Using End Function - ' - Public Async Function ExecuteNonQueryAsync(SQLCommand As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Boolean) - Return Await Task.Run(Function() ExecuteNonQuery(SQLCommand, Timeout)) + Public Function ExecuteNonQuery(pSQLCommandObject As SqlCommand, pTimeout As Integer) As Boolean + Using oConnection = GetSQLConnection() + Return ExecuteNonQueryWithConnectionObject(pSQLCommandObject, oConnection, TransactionMode.WithTransaction, Nothing, pTimeout) + End Using + End Function + + + Public Function ExecuteNonQuery(pSQLCommand As String, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean + Using oConnection = GetSQLConnection() + Return ExecuteNonQueryWithConnectionObject(pSQLCommand, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout) + End Using + End Function + + Public Function ExecuteNonQuery(pSQLCommandObject As SqlCommand, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean + Using oConnection = GetSQLConnection() + Return ExecuteNonQueryWithConnectionObject(pSQLCommandObject, pTransaction.Connection, TransactionMode.ExternalTransaction, pTransaction, pTimeout) + End Using + End Function + + Public Async Function ExecuteNonQueryAsync(pSQLCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Boolean) + Return Await Task.Run(Function() ExecuteNonQuery(pSQLCommand, pTimeout)) + End Function + + Public Async Function ExecuteNonQueryAsync(pSQLCommandObject As SqlCommand, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Boolean) + Return Await Task.Run(Function() ExecuteNonQuery(pSQLCommandObject, pTimeout)) End Function - ' Public Function ExecuteNonQueryWithConnection(pSQLCommand As String, ConnString As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) 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 = Constants.DEFAULT_TIMEOUT) As Boolean - Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction) + Public Function ExecuteNonQueryWithConnection(pSQLCommandObject As SqlCommand, ConnString As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean + Using oConnection = GetConnection(ConnString) + Return ExecuteNonQueryWithConnectionObject(pSQLCommandObject, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) + End Using + End Function + + Public Function ExecuteNonQueryWithConnectionObject(pSqlCommand As String, pSqlConnection As SqlConnection, + Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction, + Optional pTransaction As SqlTransaction = Nothing, + Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean + Dim oSQLCommand As New SqlCommand(pSqlCommand) + Return ExecuteNonQueryWithConnectionObject(oSQLCommand, pSqlConnection, pTransactionMode, pTransaction, pTimeout) + End Function + + Public Function ExecuteNonQueryWithConnectionObject(pSqlCommandObject As SqlCommand, pSqlConnection As SqlConnection, + Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction, + Optional pTransaction As SqlTransaction = Nothing, + Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Boolean + Dim oTransaction As SqlTransaction = MaybeGetTransaction(pSqlConnection, pTransactionMode, pTransaction) Try - Logger.Debug("ExecuteNonQueryWithConnectionObject: Running Command [{0}]", SqlCommand) + Logger.Debug("ExecuteNonQueryWithConnectionObject: Running Command [{0}]", pSqlCommandObject.CommandText) - Using oSQLCOmmand = SqlConnection.CreateCommand() - oSQLCOmmand.CommandText = SqlCommand - oSQLCOmmand.CommandTimeout = Timeout - oSQLCOmmand.Transaction = oTransaction - oSQLCOmmand.ExecuteNonQuery() - End Using + pSqlCommandObject.Connection = pSqlConnection + pSqlCommandObject.Transaction = oTransaction + pSqlCommandObject.CommandTimeout = pTimeout + pSqlCommandObject.ExecuteNonQuery() Return True Catch ex As Exception @@ -383,96 +440,126 @@ Public Class MSSQLServer Logger.Warn("ExecuteNonQueryWithConnectionObject: Error in ExecuteNonQueryWithConnectionObject while executing command: [{0}]-[{1}]", SqlCommand, SqlConnection.ConnectionString) Return False Finally - MaybeCommitTransaction(oTransaction, TransactionMode) + MaybeCommitTransaction(oTransaction, pTransactionMode) End Try End Function - ' - Public Function GetScalarValue(SQLQuery As String) As Object Implements IDatabase.GetScalarValue + Public Function GetScalarValue(pSqlQuery As String) As Object Implements IDatabase.GetScalarValue Using oConnection As SqlConnection = GetSQLConnection() - Return GetScalarValueWithConnectionObject(SQLQuery, oConnection) + Return GetScalarValueWithConnectionObject(pSqlQuery, oConnection) End Using End Function - ' - Public Function GetScalarValue(SQLCommand As String, Timeout As Integer) As Object Implements IDatabase.GetScalarValue + Public Function GetScalarValue(pSqlCommandObject As SqlCommand) As Object + Using oConnection As SqlConnection = GetSQLConnection() + Return GetScalarValueWithConnectionObject(pSqlCommandObject, oConnection) + End Using + End Function + + Public Function GetScalarValue(pSqlCommand As String, pTimeout As Integer) As Object Implements IDatabase.GetScalarValue Using oConnection = GetSQLConnection() - Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) + Return GetScalarValueWithConnectionObject(pSqlCommand, oConnection, TransactionMode.WithTransaction, Nothing, pTimeout) End Using End Function - ' - Public Function GetScalarValue(SQLCommand As String, Transaction As SqlTransaction, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + Public Function GetScalarValue(pSqlCommandObject As SqlCommand, pTimeout As Integer) As Object Using oConnection = GetSQLConnection() - Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.ExternalTransaction, Transaction, Timeout) + Return GetScalarValueWithConnectionObject(pSqlCommandObject, oConnection, TransactionMode.WithTransaction, Nothing, pTimeout) End Using End Function - ' - Public Async Function GetScalarValueAsync(SQLQuery As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Object) - Return Await Task.Run(Function() GetScalarValue(SQLQuery, Timeout)) + Public Function GetScalarValue(pSQLCommand As String, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + Using oConnection = GetSQLConnection() + Return GetScalarValueWithConnectionObject(pSQLCommand, oConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout) + End Using End Function - ' - Public Function GetScalarValueWithConnection(SQLCommand As String, pConnectionString As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + Public Function GetScalarValue(pSQLCommandObject As SqlCommand, pTransaction As SqlTransaction, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + Using oConnection = GetSQLConnection() + Return GetScalarValueWithConnectionObject(pSQLCommandObject, oConnection, TransactionMode.ExternalTransaction, pTransaction, pTimeout) + End Using + End Function + + Public Async Function GetScalarValueAsync(pSQLCommand As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Object) + Return Await Task.Run(Function() GetScalarValue(pSQLCommand, pTimeout)) + End Function + + Public Async Function GetScalarValueAsync(pSQLCommandObject As SqlCommand, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Task(Of Object) + Return Await Task.Run(Function() GetScalarValue(pSQLCommandObject, pTimeout)) + End Function + + Public Function GetScalarValueWithConnection(pSQLCommand As String, pConnectionString As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object Using oConnection = GetConnection(pConnectionString) - Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout) + Return GetScalarValueWithConnectionObject(pSQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, pTimeout) 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 = Constants.DEFAULT_TIMEOUT) As Object + Public Function GetScalarValueWithConnection(pSqlCommandObject As SqlCommand, pConnectionString As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + Using oConnection = GetConnection(pConnectionString) + Return GetScalarValueWithConnectionObject(pSqlCommandObject, oConnection, TransactionMode.WithTransaction, Nothing, pTimeout) + End Using + End Function - Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction) + Public Function GetScalarValueWithConnectionObject(pSqlCommand As String, pSqlConnection As SqlConnection, + Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction, + Optional pTransaction As SqlTransaction = Nothing, + Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + Dim oSQLCommand As New SqlCommand(pSqlCommand) + Return GetScalarValueWithConnectionObject(oSQLCommand, pSqlConnection, pTransactionMode, pTransaction, pTimeout) + End Function + + Public Function GetScalarValueWithConnectionObject(pSqlCommandObject As SqlCommand, pSqlConnection As SqlConnection, + Optional pTransactionMode As TransactionMode = TransactionMode.WithTransaction, + Optional pTransaction As SqlTransaction = Nothing, + Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object + + Dim oTransaction As SqlTransaction = MaybeGetTransaction(pSqlConnection, pTransactionMode, pTransaction) Dim oResult As Object = Nothing Try - Using oSQLCOmmand = SqlConnection.CreateCommand() - oSQLCOmmand.CommandText = SqlCommand - oSQLCOmmand.CommandTimeout = Timeout - oSQLCOmmand.Transaction = oTransaction + pSqlCommandObject.Connection = pSqlConnection + pSqlCommandObject.CommandTimeout = pTimeout + pSqlCommandObject.Transaction = oTransaction + oResult = pSqlCommandObject.ExecuteScalar() - oResult = oSQLCOmmand.ExecuteScalar() - End Using Catch ex As Exception Logger.Error(ex) - Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand) + Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", pSqlCommandObject) + Finally - MaybeCommitTransaction(oTransaction, TransactionMode) + MaybeCommitTransaction(oTransaction, pTransactionMode) End Try Return oResult End Function - Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String, Timeout As Integer) As Object + Public Function GetScalarValue(pSqlCommand As SqlCommand, pOutputParameter As String, Optional pTimeout As Integer = Constants.DEFAULT_TIMEOUT) As Object Try If TestCanConnect() = False Then Return Nothing End If - Logger.Debug("GetScalarValue: Running Query [{0}]", SQLCommand) + Logger.Debug("GetScalarValue: Running Query [{0}]", pSqlCommand) - If SQLCommand.CommandText.Contains(" ") Then - SQLCommand.CommandType = CommandType.Text + If pSqlCommand.CommandText.Contains(" ") Then + pSqlCommand.CommandType = CommandType.Text Else - SQLCommand.CommandType = CommandType.StoredProcedure + pSqlCommand.CommandType = CommandType.StoredProcedure End If Using oConnection As SqlConnection = GetSQLConnection() - SQLCommand.Connection = oConnection - SQLCommand.Parameters(OutputParameter).Direction = ParameterDirection.Output - SQLCommand.CommandTimeout = Timeout - SQLCommand.ExecuteNonQuery() + pSqlCommand.Connection = oConnection + pSqlCommand.Parameters(pOutputParameter).Direction = ParameterDirection.Output + pSqlCommand.CommandTimeout = pTimeout + pSqlCommand.ExecuteNonQuery() oConnection.Close() - Return SQLCommand.Parameters(OutputParameter).Value + Return pSqlCommand.Parameters(pOutputParameter).Value End Using Catch ex As Exception Logger.Error(ex) - Logger.Warn($"GetScalarValue failed SQLCommand [{SQLCommand}]") + Logger.Warn($"GetScalarValue failed SQLCommand [{pSqlCommand}]") Return Nothing End Try @@ -509,7 +596,6 @@ Public Class MSSQLServer 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) diff --git a/Database/Database.vbproj b/Database/Database.vbproj index b9f2d82c..5328db6b 100644 --- a/Database/Database.vbproj +++ b/Database/Database.vbproj @@ -99,6 +99,7 @@ + diff --git a/Database/Helpers.vb b/Database/Helpers.vb new file mode 100644 index 00000000..4d09d04b --- /dev/null +++ b/Database/Helpers.vb @@ -0,0 +1,10 @@ +Public Class Helpers + + Public Shared Function MaybeEscapeSQLCommand(pSQLCommand As String) As String + + + + End Function + + +End Class diff --git a/Database/IDatabase.vb b/Database/IDatabase.vb index a473b393..c7ea227f 100644 --- a/Database/IDatabase.vb +++ b/Database/IDatabase.vb @@ -1,4 +1,5 @@ Imports System.Data.Common +Imports System.Data.SqlClient Public Interface IDatabase ''' @@ -7,8 +8,8 @@ Public Interface IDatabase Property DBInitialized As Boolean Property CurrentConnectionString As String - Function GetDatatable(SqlCommand As String, Timeout As Integer) As DataTable - Function GetDatatable(SqlCommand As String) As DataTable + Function GetDatatable(SqlCommand As String, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable + Function GetDatatable(SqlCommand As SqlCommand, Optional Timeout As Integer = Constants.DEFAULT_TIMEOUT) As DataTable Function ExecuteNonQuery(SQLCommand As String, Timeout As Integer) As Boolean Function ExecuteNonQuery(SQLCommand As String) As Boolean diff --git a/Database/My Project/AssemblyInfo.vb b/Database/My Project/AssemblyInfo.vb index 4c91abdc..7e025ad6 100644 --- a/Database/My Project/AssemblyInfo.vb +++ b/Database/My Project/AssemblyInfo.vb @@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices - + @@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices ' übernehmen, indem Sie "*" eingeben: ' - - + + diff --git a/Interfaces/GraphQLInterface.vb b/Interfaces/GraphQLInterface.vb index fe19ea41..8b2d5ab2 100644 --- a/Interfaces/GraphQLInterface.vb +++ b/Interfaces/GraphQLInterface.vb @@ -30,11 +30,46 @@ Public Class GraphQLInterface _userEmail = Email _userPassword = Password - Dim oStore As New X509Store(StoreName.Root, StoreLocation.CurrentUser) + Dim oStoreNames As New List(Of StoreName) From {StoreName.Root, StoreName.My} + Dim oStoreLocations As New List(Of StoreLocation) From {StoreLocation.CurrentUser, StoreLocation.LocalMachine} + + Dim oCertificate As X509Certificate2 = Nothing + + For Each oStoreLocation In oStoreLocations + _logger.Debug("Checking Stores in Location [{0}]", oStoreLocation.ToString) + + For Each oStoreName In oStoreNames + oCertificate = FindCertificateByFingerprint(oStoreLocation, oStoreName, CertificateFingerprint, False) + + If oCertificate IsNot Nothing Then + _logger.Info("Certificate found in Store [{0}]/[{1}]!", oStoreName.ToString, oStoreLocation.ToString) + Exit For + End If + Next + Next + + + If oCertificate Is Nothing Then + _logger.Warn("Certificate could not be found! Exiting.") + Exit Sub + End If + + _certificate = oCertificate + + Catch ex As Exception + _logger.Error(ex) + End Try + End Sub + + Private Function FindCertificateByFingerprint(pLocation As StoreLocation, pStoreName As StoreName, pFingerprint As String, pValidOnly As Boolean) As X509Certificate2 + Try + Dim oStore As New X509Store(pStoreName, pLocation) + Dim oLocation As String = pLocation.ToString + + _logger.Info("Opening Store [{0}]/[{1}]..", oLocation, oStore.Name) oStore.Open(OpenFlags.ReadOnly) - - _logger.Debug("Available Certificates ({0}):", oStore.Certificates.Count) + _logger.Info("Available Certificates in Store [{0}]/[{1}]: [{2}]", oLocation, oStore.Name, oStore.Certificates.Count) For Each oCert In oStore.Certificates _logger.Debug("FriendlyName: {0}", oCert.FriendlyName) @@ -43,20 +78,24 @@ Public Class GraphQLInterface _logger.Debug("Fingerprint: {0}", oCert.Thumbprint) Next - _logger.Debug("Looking for Certificate with Fingerprint [{0}]", CertificateFingerprint) + _logger.Debug("Looking for Certificate with Fingerprint [{0}]", pFingerprint) + Dim oFoundCerts = oStore.Certificates.Find(X509FindType.FindByThumbprint, pFingerprint, pValidOnly) - Dim oFoundCerts = oStore.Certificates.Find(X509FindType.FindByThumbprint, CertificateFingerprint, False) + _logger.Debug("Closing store..") + oStore.Close() If oFoundCerts.Count = 0 Then - _logger.Warn("Certificate could not be found! Exiting.") - Exit Sub + _logger.Debug("Certificate with Fingerprint [{0}] not found in Store [{1}]/[{2}]", pFingerprint, oLocation, oStore.Name) + Return Nothing End If - _certificate = oFoundCerts.Item(0) + Return oFoundCerts.Item(0) Catch ex As Exception + _logger.Warn("Unexpected error while searching for certificate with Fingerprint [{0}].", pFingerprint) _logger.Error(ex) + Return Nothing End Try - End Sub + End Function Public Sub SaveCookies(Cookie As Cookie) GetCookies().Add(Cookie) @@ -144,13 +183,18 @@ Public Class GraphQLInterface Private Function GetRequest(Url As String, PostData As Byte()) As HttpWebRequest Try + ' Set supported TLS versions for WebRequest + ' Source: https://stackoverflow.com/questions/10822509/the-request-was-aborted-could-not-create-ssl-tls-secure-channel + 'SetSecurityOptions() + 'SetSecurityOptionsInsecure() + 'SetSecurityOptionsModern() + Dim oRequest As HttpWebRequest = WebRequest.Create($"{_baseUrl}{Url}") oRequest.Method = "POST" oRequest.ContentType = "application/json" oRequest.ContentLength = PostData.Length oRequest.ClientCertificates.Add(_certificate) oRequest.CookieContainer = GetCookies() - oRequest.Proxy = Nothing If Proxy Is Nothing Then @@ -167,6 +211,26 @@ Public Class GraphQLInterface End Try End Function + + Private Sub SetSecurityOptions() + ServicePointManager.SecurityProtocol = + SecurityProtocolType.Tls Or + SecurityProtocolType.Tls11 Or + SecurityProtocolType.Tls12 + End Sub + + Private Sub SetSecurityOptionsInsecure() + ServicePointManager.SecurityProtocol = + SecurityProtocolType.Tls Or + SecurityProtocolType.Tls11 Or + SecurityProtocolType.Tls12 Or + SecurityProtocolType.Ssl3 + End Sub + + Private Sub SetSecurityOptionsModern() + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 + End Sub + Private Function GetCookies() As CookieContainer If _cookieJar Is Nothing Then _cookieJar = New CookieContainer(MAX_COOKIE_COUNT, MAX_COOKIE_COUNT_PER_DOMAIN, MAX_COOKIE_SIZE) diff --git a/Interfaces/Interfaces.vbproj b/Interfaces/Interfaces.vbproj index 49d6450e..01398f6a 100644 --- a/Interfaces/Interfaces.vbproj +++ b/Interfaces/Interfaces.vbproj @@ -11,6 +11,7 @@ 512 Windows v4.6.1 + true @@ -98,6 +99,7 @@ True Application.myapp + True True diff --git a/Interfaces/My Project/AssemblyInfo.vb b/Interfaces/My Project/AssemblyInfo.vb index 0e85f009..57bc8b86 100644 --- a/Interfaces/My Project/AssemblyInfo.vb +++ b/Interfaces/My Project/AssemblyInfo.vb @@ -12,8 +12,8 @@ Imports System.Runtime.InteropServices - - + + @@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices ' übernehmen, indem Sie "*" eingeben: ' - - + + diff --git a/Interfaces/My Project/Resources.Designer.vb b/Interfaces/My Project/Resources.Designer.vb index 46a82a82..8adaa3ef 100644 --- a/Interfaces/My Project/Resources.Designer.vb +++ b/Interfaces/My Project/Resources.Designer.vb @@ -22,7 +22,7 @@ Namespace My.Resources ''' ''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. ''' - _ diff --git a/Interfaces/My Project/Settings.Designer.vb b/Interfaces/My Project/Settings.Designer.vb index 2f22163c..e383b12a 100644 --- a/Interfaces/My Project/Settings.Designer.vb +++ b/Interfaces/My Project/Settings.Designer.vb @@ -15,7 +15,7 @@ Option Explicit On Namespace My _ Partial Friend NotInheritable Class MySettings Inherits Global.System.Configuration.ApplicationSettingsBase diff --git a/Interfaces/ZUGFeRDInterface.vb b/Interfaces/ZUGFeRDInterface.vb index 1b24c0f2..f991b87d 100644 --- a/Interfaces/ZUGFeRDInterface.vb +++ b/Interfaces/ZUGFeRDInterface.vb @@ -8,41 +8,87 @@ Imports DigitalData.Modules.Logging Imports GdPicture14 Public Class ZUGFeRDInterface - Private _logConfig As LogConfig - Private _logger As Logger + Private ReadOnly _logConfig As LogConfig + Private ReadOnly _logger As Logger + Private ReadOnly _Options As ZugferdOptions + + Private ReadOnly ValidFilenames As New List(Of String) From { + PDFEmbeds.ZUGFERD_XML_FILENAME.ToUpper, + PDFEmbeds.FACTUR_X_XML_FILENAME_DE.ToUpper, + PDFEmbeds.FACTUR_X_XML_FILENAME_FR.ToUpper + } + + Private AllowedFilenames As New List(Of String) Public Enum ErrorType NoValidFile NoZugferd NoValidZugferd MissingProperties + UnsupportedFormat + UnknownError End Enum Public ReadOnly Property FileGroup As FileGroups Public ReadOnly Property PropertyValues As PropertyValues - Public Sub New(LogConfig As LogConfig, GDPictureKey As String) - _logConfig = LogConfig + Public Class ZugferdOptions + Public Property AllowFacturX_Filename As Boolean = True + Public Property AllowXRechnung_Filename As Boolean = True + End Class + + ''' + ''' Create a new instance of ZUGFeRDInterface + ''' + ''' A LogConfig object + ''' A valid GDPicture License + ''' Optional parameters to control various settings + Public Sub New(pLogConfig As LogConfig, pGDPictureKey As String, Optional pOptions As ZugferdOptions = Nothing) + _logConfig = pLogConfig _logger = _logConfig.GetLogger() + If pOptions Is Nothing Then + _Options = New ZugferdOptions() + Else + _Options = pOptions + End If + + ApplyFilenameOptions(_Options) + FileGroup = New FileGroups(_logConfig) PropertyValues = New PropertyValues(_logConfig) Try Dim oLicenseManager As New LicenseManager - oLicenseManager.RegisterKEY(GDPictureKey) + oLicenseManager.RegisterKEY(pGDPictureKey) Catch ex As Exception _logger.Warn("GDPicture License could not be registered!") _logger.Error(ex) End Try End Sub + Private Sub ApplyFilenameOptions(pOptions As ZugferdOptions) + Dim oAllowedFilenames As List(Of String) = ValidFilenames + + If pOptions.AllowFacturX_Filename = False Then + oAllowedFilenames = oAllowedFilenames. + Except(New List(Of String) From {PDFEmbeds.FACTUR_X_XML_FILENAME_FR}).ToList() + End If + + If pOptions.AllowXRechnung_Filename = False Then + oAllowedFilenames = oAllowedFilenames. + Except(New List(Of String) From {PDFEmbeds.FACTUR_X_XML_FILENAME_DE}).ToList() + End If + + AllowedFilenames = oAllowedFilenames + End Sub + + ''' ''' Validates a ZUGFeRD File and extracts the XML Document from it ''' ''' ''' - ''' Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As Object Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Path) @@ -58,7 +104,6 @@ Public Class ZUGFeRDInterface ''' ''' ''' - ''' Public Function ExtractZUGFeRDFileWithGDPicture(Stream As Stream) As Object Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Stream) @@ -72,15 +117,15 @@ Public Class ZUGFeRDInterface ''' ''' Validates a ZUGFeRD File and extracts the XML Document from it ''' - ''' + ''' ''' - ''' - Public Function ValidateZUGFeRDFileWithGDPicture(Stream As Stream) As XPathDocument + ''' The embedded xml data as an XPath document + Public Function ValidateZUGFeRDFileWithGDPicture(pStream As Stream) As XPathDocument Dim oEmbedExtractor = New PDFEmbeds(_logConfig) - Dim oAllowedExtensions = New List(Of String) From {"xml"} Try - Dim oFiles = oEmbedExtractor.Extract(Stream, oAllowedExtensions) + ' Extract XML attachments only! + Dim oFiles = oEmbedExtractor.Extract(pStream, New List(Of String) From {"xml"}) ' Attachments are in this case the files that are embedded into a pdf file, ' like for example the zugferd-invoice.xml file @@ -97,12 +142,18 @@ Public Class ZUGFeRDInterface End Try End Function - Public Function ValidateZUGFeRDFileWithGDPicture(Path As String) As XPathDocument + ''' + ''' Validates a ZUGFeRD File and extracts the XML Document from it + ''' + ''' + ''' + ''' The embedded xml data as an XPath document + Public Function ValidateZUGFeRDFileWithGDPicture(pPath As String) As XPathDocument Dim oEmbedExtractor = New PDFEmbeds(_logConfig) - Dim oAllowedExtensions = New List(Of String) From {"xml"} Try - Dim oFiles = oEmbedExtractor.Extract(Path, oAllowedExtensions) + ' Extract XML attachments only! + Dim oFiles = oEmbedExtractor.Extract(pPath, New List(Of String) From {"xml"}) ' Attachments are in this case the files that are embedded into a pdf file, ' like for example the zugferd-invoice.xml file @@ -119,34 +170,38 @@ Public Class ZUGFeRDInterface End Try End Function - Private Function HandleEmbeddedFiles(Results As List(Of PDFEmbeds.EmbeddedFile)) As XPathDocument + Private Function HandleEmbeddedFiles(pResults As List(Of PDFEmbeds.EmbeddedFile)) As XPathDocument Dim oXmlDocument As XPathDocument - If Results Is Nothing Then + If pResults Is Nothing Then Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil die Attachments nicht gelesen werden konnten.") End If - If Results.Count = 0 Then + If pResults.Count = 0 Then Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil sie keine Attachments enthält.") End If - Dim oValidFilenames As New List(Of String) From { - PDFEmbeds.ZUGFERD_XML_FILENAME.ToUpper, - PDFEmbeds.FACTUR_X_XML_FILENAME_DE.ToUpper, - PDFEmbeds.FACTUR_X_XML_FILENAME_FR.ToUpper - } - ' Find the first file which filename matches the valid filenames for embedded invoice files - Dim oFoundResult As PDFEmbeds.EmbeddedFile = Results. - Where(Function(result) oValidFilenames.Contains(result.FileName.ToUpper)). + Dim oValidResult As PDFEmbeds.EmbeddedFile = pResults. + Where(Function(result) ValidFilenames.Contains(result.FileName.ToUpper)). FirstOrDefault() - If oFoundResult Is Nothing Then - Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil die zugferd-invoice.xml nicht gefunden wurde.") + If oValidResult Is Nothing Then + Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil keine entsprechende XML-Datei gefunden wurde.") + End If + + ' Search the embedded files for the ones which are allowed as per the configuration. + ' The config might say, allow ZUGFeRD but not Factur-X. + Dim oAllowedResult As PDFEmbeds.EmbeddedFile = pResults. + Where(Function(result) AllowedFilenames.Contains(result.FileName.ToUpper)). + FirstOrDefault() + + If oAllowedResult Is Nothing Then + Throw New ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Datei ist eine ZUGFeRD Datei, aber das Format wird nicht unterstützt.") End If Try - Using oStream As New MemoryStream(oFoundResult.FileContents) + Using oStream As New MemoryStream(oAllowedResult.FileContents) oXmlDocument = New XPathDocument(oStream) End Using @@ -162,9 +217,9 @@ Public Class ZUGFeRDInterface End Try End Function - Public Function SerializeZUGFeRDDocument(Document As XPathDocument) As Object + Public Function SerializeZUGFeRDDocument(pDocument As XPathDocument) As Object Try - Dim oNavigator As XPathNavigator = Document.CreateNavigator() + Dim oNavigator As XPathNavigator = pDocument.CreateNavigator() Dim oReader As XmlReader Dim oResult = Nothing diff --git a/Interfaces/ZUGFeRDInterface/PDFEmbeds.vb b/Interfaces/ZUGFeRDInterface/PDFEmbeds.vb index b9143772..2385a93b 100644 --- a/Interfaces/ZUGFeRDInterface/PDFEmbeds.vb +++ b/Interfaces/ZUGFeRDInterface/PDFEmbeds.vb @@ -28,7 +28,7 @@ Public Class PDFEmbeds Public Function Extract(FilePath As String, AllowedExtensions As List(Of String)) As List(Of EmbeddedFile) Dim oFile As New List(Of EmbeddedFile) Dim oFileInfo As FileInfo - Dim oExtensions = AllowedExtensions.ConvertAll(New Converter(Of String, String)(Function(ext) ext.ToUpper)) + Dim oExtensions = AllowedExtensions.Select(Function(ext) ext.ToUpper).ToList() Logger.Debug("Extracting embedded files from [{0}]", FilePath) @@ -69,7 +69,7 @@ Public Class PDFEmbeds ''' List of allowed extensions to be extracted Public Function Extract(Stream As Stream, AllowedExtensions As List(Of String)) As List(Of EmbeddedFile) Dim oResults As New List(Of EmbeddedFile) - Dim oExtensions = AllowedExtensions.ConvertAll(New Converter(Of String, String)(Function(ext) ext.ToUpper)) + Dim oExtensions = AllowedExtensions.Select(Function(ext) ext.ToUpper).ToList() Logger.Debug("Extracting embedded files from stream") diff --git a/Interfaces/app.config b/Interfaces/app.config index d5fed9f7..fe3622a3 100644 --- a/Interfaces/app.config +++ b/Interfaces/app.config @@ -1,11 +1,11 @@ - + - - + + - \ No newline at end of file + diff --git a/Jobs/EDMI/ADSync/ADSyncArgs.vb b/Jobs/ADSync/ADSyncArgs.vb similarity index 100% rename from Jobs/EDMI/ADSync/ADSyncArgs.vb rename to Jobs/ADSync/ADSyncArgs.vb diff --git a/Jobs/EDMI/ADSync/ADSyncJob.vb b/Jobs/ADSync/ADSyncJob.vb similarity index 100% rename from Jobs/EDMI/ADSync/ADSyncJob.vb rename to Jobs/ADSync/ADSyncJob.vb diff --git a/Jobs/App.config b/Jobs/App.config index 6117847c..db14e04e 100644 --- a/Jobs/App.config +++ b/Jobs/App.config @@ -1,14 +1,14 @@ - + - + - - + + - \ No newline at end of file + diff --git a/Jobs/Exceptions.vb b/Jobs/Exceptions.vb index 17d69987..bdd4c341 100644 --- a/Jobs/Exceptions.vb +++ b/Jobs/Exceptions.vb @@ -40,6 +40,14 @@ Public Class Exceptions End Sub End Class + Public Class UnsupportedFerdException + Inherits ApplicationException + + Public Sub New() + MyBase.New("ZUGFeRD document found but is not supported!") + End Sub + End Class + Public Class NoFerdsException Inherits ApplicationException diff --git a/Jobs/EDMI/GraphQL/GraphQLArgs.vb b/Jobs/GraphQL/GraphQLArgs.vb similarity index 100% rename from Jobs/EDMI/GraphQL/GraphQLArgs.vb rename to Jobs/GraphQL/GraphQLArgs.vb diff --git a/Jobs/EDMI/GraphQL/GraphQLConfig.vb b/Jobs/GraphQL/GraphQLConfig.vb similarity index 100% rename from Jobs/EDMI/GraphQL/GraphQLConfig.vb rename to Jobs/GraphQL/GraphQLConfig.vb diff --git a/Jobs/EDMI/GraphQL/GraphQLJob.vb b/Jobs/GraphQL/GraphQLJob.vb similarity index 100% rename from Jobs/EDMI/GraphQL/GraphQLJob.vb rename to Jobs/GraphQL/GraphQLJob.vb diff --git a/Jobs/EDMI/GraphQL/GraphQLQuery.vb b/Jobs/GraphQL/GraphQLQuery.vb similarity index 100% rename from Jobs/EDMI/GraphQL/GraphQLQuery.vb rename to Jobs/GraphQL/GraphQLQuery.vb diff --git a/Jobs/Jobs.vbproj b/Jobs/Jobs.vbproj index 50dee6c2..496f0acf 100644 --- a/Jobs/Jobs.vbproj +++ b/Jobs/Jobs.vbproj @@ -13,6 +13,7 @@ v4.6.1 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 true + AnyCPU @@ -90,17 +91,17 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/Jobs/My Project/AssemblyInfo.vb b/Jobs/My Project/AssemblyInfo.vb index a6872d43..97579bab 100644 --- a/Jobs/My Project/AssemblyInfo.vb +++ b/Jobs/My Project/AssemblyInfo.vb @@ -12,8 +12,8 @@ Imports System.Runtime.InteropServices - - + + @@ -30,5 +30,5 @@ Imports System.Runtime.InteropServices ' Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern ' übernehmen, indem Sie "*" eingeben: - - + + diff --git a/Jobs/My Project/Settings.Designer.vb b/Jobs/My Project/Settings.Designer.vb index b89e781b..0d240d08 100644 --- a/Jobs/My Project/Settings.Designer.vb +++ b/Jobs/My Project/Settings.Designer.vb @@ -14,7 +14,7 @@ Option Explicit On _ Partial Friend NotInheritable Class Settings Inherits Global.System.Configuration.ApplicationSettingsBase diff --git a/Jobs/EDMI/ZUGFeRD/EmailData.vb b/Jobs/ZUGFeRD/EmailData.vb similarity index 100% rename from Jobs/EDMI/ZUGFeRD/EmailData.vb rename to Jobs/ZUGFeRD/EmailData.vb diff --git a/Jobs/EDMI/ZUGFeRD/EmailFunctions.vb b/Jobs/ZUGFeRD/EmailFunctions.vb similarity index 95% rename from Jobs/EDMI/ZUGFeRD/EmailFunctions.vb rename to Jobs/ZUGFeRD/EmailFunctions.vb index cb697665..9dd4c1ae 100644 --- a/Jobs/EDMI/ZUGFeRD/EmailFunctions.vb +++ b/Jobs/ZUGFeRD/EmailFunctions.vb @@ -83,13 +83,14 @@ Public Class EmailFunctions Dim oFinalBodyText = String.Format(EmailStrings.EMAIL_WRAPPING_TEXT.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal), oCompleteBodyText) Dim oEmailAddress = pEmailData.From - Dim oAttachment = pEmailData.Attachment - If oAttachment <> String.Empty Then - _logger.Debug($"Attachment_String [{oAttachment}]!") - If IO.File.Exists(oAttachment) = False Then - _logger.Info($"Attachment.File [{oAttachment}] is not existing!!!") + Dim oAttachmentPath = pEmailData.Attachment + If oAttachmentPath <> String.Empty Then + _logger.Debug($"Attachment_String [{oAttachmentPath}]!") + If IO.File.Exists(oAttachmentPath) = False Then + _logger.Info($"Attachment.File [{oAttachmentPath}] is not existing!!!") End If End If + Dim oAttachmentPathEscaped = oAttachmentPath.Replace("'", "''") If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then _logger.Warn("Could not find email-address for MessageId {0}", MessageId) @@ -133,7 +134,7 @@ Public Class EmailFunctions ,'{oFinalBodyText}' ,'{SourceProcedure}' ,'{oCreatedWho}' - ,'{oAttachment}')" + ,'{oAttachmentPathEscaped}')" _mssql.ExecuteNonQuery(oInsert) Else 'If oDTResult.Rows.Count = 0 Then diff --git a/Jobs/EDMI/ZUGFeRD/EmailStrings.vb b/Jobs/ZUGFeRD/EmailStrings.vb similarity index 93% rename from Jobs/EDMI/ZUGFeRD/EmailStrings.vb rename to Jobs/ZUGFeRD/EmailStrings.vb index 3def7e00..b29e11ea 100644 --- a/Jobs/EDMI/ZUGFeRD/EmailStrings.vb +++ b/Jobs/ZUGFeRD/EmailStrings.vb @@ -37,4 +37,8 @@
  • Betrags-Werte weisen ungültiges Format auf (25,01 anstatt 25.01)
  • " + + Public Const EMAIL_UNSUPPORTED_DOCUMENT = " +

    Ihre Email enthielt ein ZUGFeRD Dokument, welches aber zur Zeit noch nicht unsterstützt wird.

    + " End Class diff --git a/Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb b/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb similarity index 95% rename from Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb rename to Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb index 11914534..cb09f2aa 100644 --- a/Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb +++ b/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb @@ -26,35 +26,33 @@ Public Class ImportZUGFeRDFiles Private Const DIRECTORY_DONT_MOVE = "DIRECTORY_DONT_MOVE" - ' List of allowed extensions for PDF/A Attachments ' This list should not contain xml so the zugferd xml file will be filtered out - Private ReadOnly AllowedExtensions As List(Of String) = New List(Of String) From {"docx", "doc", "pdf", "xls", "xlsx", "ppt", "pptx", "txt"} + Private ReadOnly AllowedExtensions As New List(Of String) From {"docx", "doc", "pdf", "xls", "xlsx", "ppt", "pptx", "txt"} Private ReadOnly _logger As Logger Private ReadOnly _logConfig As LogConfig - Private ReadOnly _zugferd As ZUGFeRDInterface Private ReadOnly _firebird As Firebird Private ReadOnly _filesystem As Filesystem.File - Private ReadOnly _EmailOutAccountId As Integer Private ReadOnly _mssql As MSSQLServer Private ReadOnly _email As EmailFunctions + Private ReadOnly _gdpictureLicenseKey As String + Private _zugferd As ZUGFeRDInterface + Private _EmailOutAccountId As Integer - Public Sub New(LogConfig As LogConfig, Firebird As Firebird, pEmailOutAccount As Integer, pPortalName As String, Optional MSSQL As MSSQLServer = Nothing) + Public Sub New(LogConfig As LogConfig, Firebird As Firebird, Optional MSSQL As MSSQLServer = Nothing) _logConfig = LogConfig _logger = LogConfig.GetLogger() _firebird = Firebird _filesystem = New Filesystem.File(_logConfig) _mssql = MSSQL - _EmailOutAccountId = pEmailOutAccount _email = New EmailFunctions(LogConfig, _mssql, _firebird) _logger.Debug("Registering GDPicture License") If _mssql IsNot Nothing Then Dim oSQL = "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'" - Dim oLicenseKey As String = _mssql.GetScalarValue(oSQL) - _zugferd = New ZUGFeRDInterface(_logConfig, oLicenseKey) + _gdpictureLicenseKey = _mssql.GetScalarValue(oSQL) Else _logger.Warn("GDPicture License could not be registered! MSSQL is not enabled!") Throw New ArgumentNullException("MSSQL") @@ -125,6 +123,14 @@ Public Class ImportZUGFeRDFiles Dim oPropertyExtractor = New PropertyValues(_logConfig) Dim oAttachmentExtractor = New PDFEmbeds(_logConfig) + _EmailOutAccountId = oArgs.EmailOutProfileId + + Dim oOptions As New ZUGFeRDInterface.ZugferdOptions() With { + .AllowFacturX_Filename = oArgs.AllowFacturX, + .AllowXRechnung_Filename = oArgs.AllowXRechnung + } + _zugferd = New ZUGFeRDInterface(_logConfig, _gdpictureLicenseKey, oOptions) + _logger.Debug("Starting Job {0}", [GetType].Name) Try @@ -238,6 +244,10 @@ Public Class ImportZUGFeRDFiles oEmailAttachmentFiles.Add(oFile) Continue For + Case ZUGFeRDInterface.ErrorType.UnsupportedFormat + _logger.Info("File [{0}] is an unsupported ZUFeRD document format!") + Throw New UnsupportedFerdException() + Case ZUGFeRDInterface.ErrorType.NoValidZugferd _logger.Warn("File [{0}] is an Incorrectly formatted ZUGFeRD document!", oFile.Name) Throw New InvalidFerdException() @@ -380,6 +390,18 @@ Public Class ImportZUGFeRDFiles _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oArgs.NamePortal) AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction) + Catch ex As UnsupportedFerdException + _logger.Error(ex) + + ' When UnsupportedFerdException is thrown, we don't have a MD5Hash yet. + ' That 's why we set it to String.Empty here. + Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format", oFBTransaction) + + Dim oBody = EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT + Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) + _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "UnsupportedFerdException", _EmailOutAccountId, oArgs.NamePortal) + AddRejectedState(oMessageId, "UnsupportedFerdException", "Nicht unterstütztes Datenformat", "", oSQLTransaction) + Catch ex As InvalidFerdException _logger.Error(ex) diff --git a/Jobs/EDMI/ZUGFeRD/WorkerArgs.vb b/Jobs/ZUGFeRD/WorkerArgs.vb similarity index 84% rename from Jobs/EDMI/ZUGFeRD/WorkerArgs.vb rename to Jobs/ZUGFeRD/WorkerArgs.vb index 662f107f..a34a90b0 100644 --- a/Jobs/EDMI/ZUGFeRD/WorkerArgs.vb +++ b/Jobs/ZUGFeRD/WorkerArgs.vb @@ -14,10 +14,16 @@ Public Class WorkerArgs ' Property Parameter Public PropertyMap As New Dictionary(Of String, XmlItemProperty) + ' Email Parameter + Public EmailOutProfileId As Integer = 0 + ' Misc Flag Parameters Public InsertIntoSQLServer As Boolean = False Public ExceptionEmailAddress As String = Nothing Public IgnoreRejectionStatus As Boolean = False Public MaxAttachmentSizeInMegaBytes As Integer = -1 Public NamePortal As String = "NO PORTAL_NAME IN CONFIG" + + Public AllowFacturX As Boolean = True + Public AllowXRechnung As Boolean = True End Class \ No newline at end of file diff --git a/Language/My Project/AssemblyInfo.vb b/Language/My Project/AssemblyInfo.vb index 14982058..14be03cb 100644 --- a/Language/My Project/AssemblyInfo.vb +++ b/Language/My Project/AssemblyInfo.vb @@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices - + @@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices ' übernehmen, indem Sie "*" eingeben: ' - - + + diff --git a/Language/StringEx.vb b/Language/StringEx.vb index a4cb6f4d..2fcfa2b1 100644 --- a/Language/StringEx.vb +++ b/Language/StringEx.vb @@ -12,4 +12,15 @@ Public Module StringEx If String.IsNullOrEmpty(pString) Then Return pString Return pString.Substring(0, Math.Min(pLength, pString.Length)) End Function + + ''' + ''' Replaces single quotes in text for SQL Commands. + ''' + ''' The string + ''' The escaped string. + + Public Function EscapeForSQL(pString As String) As String + If String.IsNullOrEmpty(pString) Then Return pString + Return pString.Replace("'", "''") + End Function End Module diff --git a/Mailfunctions/Mail.vb b/Mailfunctions/Mail.vb deleted file mode 100644 index a9d612fa..00000000 --- a/Mailfunctions/Mail.vb +++ /dev/null @@ -1,13 +0,0 @@ -Imports DigitalData.Modules.Logging -Public Class Mail - Private LogConfig As LogConfig - Private Logger As DigitalData.Modules.Logging.Logger - Public Sub New(LogConfig As LogConfig) - LogConfig = LogConfig - Logger = LogConfig.GetLogger() - Logger.Info("MailingClass initialized") - End Sub - Public Function Connecttest() - - End Function -End Class diff --git a/Mailfunctions/Mailfunctions.vbproj b/Mailfunctions/Mailfunctions.vbproj deleted file mode 100644 index 78248113..00000000 --- a/Mailfunctions/Mailfunctions.vbproj +++ /dev/null @@ -1,123 +0,0 @@ - - - - - Debug - AnyCPU - {C9827B8D-9EF9-411A-A6BF-4807794F8C8F} - Library - Mailfunctions - Mailfunctions - 512 - Windows - v4.7.2 - true - - - true - full - true - true - bin\Debug\ - Mailfunctions.xml - 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 - - - pdbonly - false - true - true - bin\Release\ - Mailfunctions.xml - 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 - - - On - - - Binary - - - Off - - - On - - - - P:\Visual Studio Projekte\Bibliotheken\Limilabs\Mail.dll\Mail.dll - - - - ..\packages\NLog.4.7.15\lib\net45\NLog.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - Application.myapp - - - True - True - Resources.resx - - - True - Settings.settings - True - - - - - VbMyResourcesResXFileCodeGenerator - Resources.Designer.vb - My.Resources - Designer - - - - - MyApplicationCodeGenerator - Application.Designer.vb - - - SettingsSingleFileGenerator - My - Settings.Designer.vb - - - - - - {903b2d7d-3b80-4be9-8713-7447b704e1b0} - Logging - - - - \ No newline at end of file diff --git a/Mailfunctions/My Project/Application.Designer.vb b/Mailfunctions/My Project/Application.Designer.vb deleted file mode 100644 index 88dd01c7..00000000 --- a/Mailfunctions/My Project/Application.Designer.vb +++ /dev/null @@ -1,13 +0,0 @@ -'------------------------------------------------------------------------------ -' -' This code was generated by a tool. -' Runtime Version:4.0.30319.42000 -' -' Changes to this file may cause incorrect behavior and will be lost if -' the code is regenerated. -' -'------------------------------------------------------------------------------ - -Option Strict On -Option Explicit On - diff --git a/Mailfunctions/My Project/Application.myapp b/Mailfunctions/My Project/Application.myapp deleted file mode 100644 index 758895de..00000000 --- a/Mailfunctions/My Project/Application.myapp +++ /dev/null @@ -1,10 +0,0 @@ - - - false - false - 0 - true - 0 - 1 - true - diff --git a/Mailfunctions/My Project/AssemblyInfo.vb b/Mailfunctions/My Project/AssemblyInfo.vb deleted file mode 100644 index 0d865ee5..00000000 --- a/Mailfunctions/My Project/AssemblyInfo.vb +++ /dev/null @@ -1,35 +0,0 @@ -Imports System -Imports System.Reflection -Imports System.Runtime.InteropServices - -' Allgemeine Informationen über eine Assembly werden über die folgenden -' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -' die einer Assembly zugeordnet sind. - -' Werte der Assemblyattribute überprüfen - - - - - - - - - - -'Die folgende GUID wird für die typelib-ID verwendet, wenn dieses Projekt für COM verfügbar gemacht wird. - - -' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: -' -' Hauptversion -' Nebenversion -' Buildnummer -' Revision -' -' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, -' indem Sie "*" wie unten gezeigt eingeben: -' - - - diff --git a/Mailfunctions/My Project/Resources.Designer.vb b/Mailfunctions/My Project/Resources.Designer.vb deleted file mode 100644 index 702d170b..00000000 --- a/Mailfunctions/My Project/Resources.Designer.vb +++ /dev/null @@ -1,62 +0,0 @@ -'------------------------------------------------------------------------------ -' -' This code was generated by a tool. -' Runtime Version:4.0.30319.42000 -' -' Changes to this file may cause incorrect behavior and will be lost if -' the code is regenerated. -' -'------------------------------------------------------------------------------ - -Option Strict On -Option Explicit On - - -Namespace My.Resources - - 'This class was auto-generated by the StronglyTypedResourceBuilder - 'class via a tool like ResGen or Visual Studio. - 'To add or remove a member, edit your .ResX file then rerun ResGen - 'with the /str option, or rebuild your VS project. - ''' - ''' A strongly-typed resource class, for looking up localized strings, etc. - ''' - _ - Friend Module Resources - - Private resourceMan As Global.System.Resources.ResourceManager - - Private resourceCulture As Global.System.Globalization.CultureInfo - - ''' - ''' Returns the cached ResourceManager instance used by this class. - ''' - _ - Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager - Get - If Object.ReferenceEquals(resourceMan, Nothing) Then - Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Mailfunctions.Resources", GetType(Resources).Assembly) - resourceMan = temp - End If - Return resourceMan - End Get - End Property - - ''' - ''' Overrides the current thread's CurrentUICulture property for all - ''' resource lookups using this strongly typed resource class. - ''' - _ - Friend Property Culture() As Global.System.Globalization.CultureInfo - Get - Return resourceCulture - End Get - Set(ByVal value As Global.System.Globalization.CultureInfo) - resourceCulture = value - End Set - End Property - End Module -End Namespace diff --git a/Mailfunctions/My Project/Resources.resx b/Mailfunctions/My Project/Resources.resx deleted file mode 100644 index af7dbebb..00000000 --- a/Mailfunctions/My Project/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Mailfunctions/My Project/Settings.Designer.vb b/Mailfunctions/My Project/Settings.Designer.vb deleted file mode 100644 index fd3119d4..00000000 --- a/Mailfunctions/My Project/Settings.Designer.vb +++ /dev/null @@ -1,73 +0,0 @@ -'------------------------------------------------------------------------------ -' -' This code was generated by a tool. -' Runtime Version:4.0.30319.42000 -' -' Changes to this file may cause incorrect behavior and will be lost if -' the code is regenerated. -' -'------------------------------------------------------------------------------ - -Option Strict On -Option Explicit On - - -Namespace My - - _ - Partial Friend NotInheritable Class MySettings - Inherits Global.System.Configuration.ApplicationSettingsBase - - Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings) - -#Region "My.Settings Auto-Save Functionality" -#If _MyType = "WindowsForms" Then - Private Shared addedHandler As Boolean - - Private Shared addedHandlerLockObject As New Object - - _ - Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs) - If My.Application.SaveMySettingsOnExit Then - My.Settings.Save() - End If - End Sub -#End If -#End Region - - Public Shared ReadOnly Property [Default]() As MySettings - Get - -#If _MyType = "WindowsForms" Then - If Not addedHandler Then - SyncLock addedHandlerLockObject - If Not addedHandler Then - AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings - addedHandler = True - End If - End SyncLock - End If -#End If - Return defaultInstance - End Get - End Property - End Class -End Namespace - -Namespace My - - _ - Friend Module MySettingsProperty - - _ - Friend ReadOnly Property Settings() As Global.Mailfunctions.My.MySettings - Get - Return Global.Mailfunctions.My.MySettings.Default - End Get - End Property - End Module -End Namespace diff --git a/Mailfunctions/My Project/Settings.settings b/Mailfunctions/My Project/Settings.settings deleted file mode 100644 index 85b890b3..00000000 --- a/Mailfunctions/My Project/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Mailfunctions/packages.config b/Mailfunctions/packages.config deleted file mode 100644 index 984ab728..00000000 --- a/Mailfunctions/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Messaging/Limilab.vb b/Messaging/Limilab.vb index fc583368..69bca208 100644 --- a/Messaging/Limilab.vb +++ b/Messaging/Limilab.vb @@ -113,17 +113,21 @@ Public Class Limilab End Try End Function Public Function IMAPGetMessageIDs_AllMails() As List(Of Long) - Dim oListuids As New List(Of Long) Logger.Debug("Starting IMAPGetMessageIDs ...") If Initialized = False Then Return Nothing End If Try - Dim oConnect As Boolean = ImapConnect() + Dim oConnectionSuccessful As Boolean = ImapConnect() + Dim oListuids As List(Of Long) - If oConnect = True Then + If oConnectionSuccessful = True Then + Logger.Debug("Checking for new messages..") oListuids = ImapGetMessageIDs_All() CURR_ListUIDs = oListuids + Else + Logger.Warn("Connection was NOT successful. Returning Nothing.") + Return Nothing End If Return oListuids Catch ex As Exception @@ -223,10 +227,13 @@ Public Class Limilab Private Function ImapGetMessageIDs_All() As List(Of Long) Dim oListuids As New List(Of Long) Try + Logger.Debug("Opening Inbox..") CurrentImapObject.SelectInbox() + Logger.Debug("Searching messages..") oListuids = CurrentImapObject.Search(Flag.All) + Logger.Debug("[{0}] messages found.", oListuids.Count) Return oListuids Catch ex As Exception Logger.Error(ex) diff --git a/Modules.sln b/Modules.sln index 1ee4622c..900c70b0 100644 --- a/Modules.sln +++ b/Modules.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31005.135 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32929.385 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Base", "Base\Base.vbproj", "{6EA0C51F-C2B1-4462-8198-3DE0B32B74F8}" EndProject @@ -27,8 +27,6 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Logging", "Logging\Logging. EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Logging.Test", "Logging.Test\Logging.Test.vbproj", "{3207D8E7-36E3-4714-9B03-7B5B3D6D351A}" EndProject -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Mailfunctions", "Mailfunctions\Mailfunctions.vbproj", "{C9827B8D-9EF9-411A-A6BF-4807794F8C8F}" -EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Patterns", "Patterns\Patterns.vbproj", "{7C3B0C7E-59FE-4E1A-A655-27AE119F9444}" EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Windows", "Windows\Windows.vbproj", "{5EFAEF9B-90B9-4F05-9F70-F79AD77FFF86}" @@ -39,6 +37,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ZooFlow", "ZooFlow\ZooFlow. EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Messaging", "Messaging\Messaging.vbproj", "{AF664D85-0A4B-4BAB-A2F8-83110C06553A}" EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Database.Test", "Database.Test\Database.Test.vbproj", "{91B4DFC0-543C-43A7-A9E0-6817DCA277EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -93,10 +93,6 @@ Global {3207D8E7-36E3-4714-9B03-7B5B3D6D351A}.Debug|Any CPU.Build.0 = Debug|Any CPU {3207D8E7-36E3-4714-9B03-7B5B3D6D351A}.Release|Any CPU.ActiveCfg = Release|Any CPU {3207D8E7-36E3-4714-9B03-7B5B3D6D351A}.Release|Any CPU.Build.0 = Release|Any CPU - {C9827B8D-9EF9-411A-A6BF-4807794F8C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C9827B8D-9EF9-411A-A6BF-4807794F8C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C9827B8D-9EF9-411A-A6BF-4807794F8C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C9827B8D-9EF9-411A-A6BF-4807794F8C8F}.Release|Any CPU.Build.0 = Release|Any CPU {7C3B0C7E-59FE-4E1A-A655-27AE119F9444}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7C3B0C7E-59FE-4E1A-A655-27AE119F9444}.Debug|Any CPU.Build.0 = Debug|Any CPU {7C3B0C7E-59FE-4E1A-A655-27AE119F9444}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -117,6 +113,10 @@ Global {AF664D85-0A4B-4BAB-A2F8-83110C06553A}.Debug|Any CPU.Build.0 = Debug|Any CPU {AF664D85-0A4B-4BAB-A2F8-83110C06553A}.Release|Any CPU.ActiveCfg = Release|Any CPU {AF664D85-0A4B-4BAB-A2F8-83110C06553A}.Release|Any CPU.Build.0 = Release|Any CPU + {91B4DFC0-543C-43A7-A9E0-6817DCA277EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91B4DFC0-543C-43A7-A9E0-6817DCA277EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91B4DFC0-543C-43A7-A9E0-6817DCA277EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91B4DFC0-543C-43A7-A9E0-6817DCA277EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ZooFlow/Environment.vb b/ZooFlow/Environment.vb index b902e618..10ba683f 100644 --- a/ZooFlow/Environment.vb +++ b/ZooFlow/Environment.vb @@ -3,8 +3,8 @@ Public Class Environment Public Property User As New State.UserState Public Property Settings As New State.SettingsState - Public Property Service As State.ServiceState + Public Property Service As New State.ServiceState Public Property Database As MSSQLServer Public Property DatabaseIDB As MSSQLServer - Public Property Modules As Dictionary(Of String, State.ModuleState) + Public Property Modules As New Dictionary(Of String, State.ModuleState) End Class