diff --git a/Service.EDMIService/EDMIService.vb b/Service.EDMIService/EDMIService.vb index fbae51ff..456aaa28 100644 --- a/Service.EDMIService/EDMIService.vb +++ b/Service.EDMIService/EDMIService.vb @@ -9,7 +9,8 @@ Imports System.ServiceModel.Description Imports DigitalData.Services.EDMIService.Messages Imports DigitalData.Modules.EDMI.API.Rights Imports DigitalData.Services.EDMIService.Exceptions - +Imports DigitalData.Services.EDMIService.GlobalState +Imports DigitalData.Services.EDMIService.FileStorage Public Class EDMIService @@ -54,16 +55,110 @@ Public Class EDMIService _Logger.Debug("New Request by User [{0}]", _Username) End Sub - Private Function StripDomainFromUsername(UserName As String) - If UserName.Contains("\") Then - Return UserName.Split("\")(1) - ElseIf UserName.Contains("@") Then - Return UserName.Split("@")(0) - Else - Return UserName - End If + Public Function NewFile(Data As NewFile.NewFileRequest) As NewFile.NewFileResponse Implements IEDMIService.NewFile + _Logger.Debug("Start of Method [NewFile]") + + Try + Dim oNewObjectIdSQL = $"DECLARE @NEW_IDB_OBJ_ID BIGINT + EXEC PRIDB_NEW_OBJECT '{Data.KindType}','{Data.Who}','{Data.BusinessEntity}',0, @IDB_OBJ_ID = @NEW_IDB_OBJ_ID OUTPUT; + SELECT @NEW_IDB_OBJ_ID" + Dim oObjectId As Long = MSSQL_IDB.GetScalarValue(oNewObjectIdSQL) + _Logger.Info("New Object with Id [{0}] created!", oObjectId) + + If IsNothing(oObjectId) Then + LogAndThrow("Could not create new ObjectId!") + End If + + '--------------------------------------------------------------------------- + + ' Find ObjectStore by Title + _Logger.Debug("Checking for DataStore [{0}].", Data.StoreName) + Dim oStore = GlobalState.ObjectStores. + Where(Function(store) store.Path.Equals(Data.StoreName, StringComparison.OrdinalIgnoreCase)). + SingleOrDefault() + + If oStore Is Nothing Then + LogAndThrow($"DataStore [{Data.StoreName}] does not exist. Exiting.") + End If + + ' Get Store base path + Dim oBasePath As String = oStore.Path + _Logger.Debug("Store BasePath is [{0}]", oBasePath) + + ' Get directory by DateImported or, if not supplied, by current date + Dim oSubDirectory As String + If IsNothing(Data.FileImportedAt) Then + oSubDirectory = GetDateSubDirectory(Now) + Else + oSubDirectory = GetDateSubDirectory(Data.FileImportedAt) + End If + _Logger.Debug("Subdirectory is [{0}]", oSubDirectory) + + ' Check and create final path, if necessary + Dim oFinalPath = Path.Combine(oBasePath, oSubDirectory) + If Not Directory.Exists(oFinalPath) Then + Try + _Logger.Debug("Path does not exist, creating: [{0}]", oFinalPath) + Directory.CreateDirectory(oFinalPath) + _Logger.Debug("Created folder [{0}]", oFinalPath) + Catch ex As Exception + Throw GetFault(ex) + End Try + End If + _Logger.Debug("Final Directory is [{0}]", oFinalPath) + + ' Get filename + Dim oKeepFileName As Boolean = False + If oStore.IsArchive Then + _Logger.Debug("Object Store is an archive: [{0}]", oStore.IsArchive) + oKeepFileName = True + End If + + Dim oFileName As String = GetFileObjectFileName(oObjectId, Data.FileName, oKeepFileName) + _Logger.Debug("Filename is [{0}]", oFileName) + + Dim oFileObjectPath As String = Path.Combine(oFinalPath, oFileName) + Dim oFileObjectInfo As FileInfo = New FileInfo(oFileObjectPath) + + Dim oFileObjectSize As Long = Data.FileContents.Length + Dim oFileObjectExtension As String = oFileObjectInfo.Extension.Substring(1) + Dim oFileObjectName As String = oFileObjectInfo.Name + + _Logger.Debug("File Information for [{0}]:", oFileObjectName) + _Logger.Debug("Size: [{0}]", oFileObjectSize) + _Logger.Debug("Extension: [{0}]", oFileObjectExtension) + _Logger.Debug("Checksum: [{0}]", Data.FileChecksum) + + Try + Using oStream = New FileStream(oFileObjectPath, FileMode.Create, FileAccess.Write) + _Logger.Info("ImportFile: Saving file to path [{0}]", oFileObjectPath) + _Logger.Info("ImportFile: Content Length: {0}", oFileObjectSize) + + oStream.Write(Data.FileContents, 0, oFileObjectSize) + oStream.Flush(True) + oStream.Close() + End Using + Catch ex As Exception + _Logger.Error(ex) + LogAndThrow("Could not write file to disk!") + End Try + + ' Insert into DB + Dim oSQL As String = $"EXEC PRIDB_NEW_IDBFO '{oFileObjectPath}', '{oFileObjectName}', '{oFileObjectExtension}',{oFileObjectSize},{Data.FileChecksum} ,'{Data.Who}','{oObjectId}',{oStore.Id}" + Dim oResult As Boolean = MSSQL_IDB.ExecuteNonQuery(oSQL) + + If oResult = False Then + LogAndThrow("IDB FileObject could not be created!") + End If + + Return New NewFile.NewFileResponse(oObjectId) + Catch ex As FaultException + Return New NewFile.NewFileResponse(ex) + + End Try End Function + #Region "=== Heartbeat ===" Public Function Heartbeat() As Boolean Implements IEDMIService.Heartbeat Return True @@ -288,56 +383,56 @@ Public Class EDMIService ''' Imports a file according to ObjectStoreId ''' ''' - Public Function ImportFile(Data As DocumentImportRequest) As DocumentImportResponse Implements IEDMIService.ImportFile - Dim oObjectStore = GlobalState.ObjectStores.First() - Dim EDMIPath = New EDMI.File.Path(LogConfig, oObjectStore.Path) + 'Public Function ImportFile(Data As DocumentImportRequest) As DocumentImportResponse Implements IEDMIService.ImportFile + ' Dim oObjectStore = GlobalState.ObjectStores.First() + ' Dim EDMIPath = New EDMI.File.Path(LogConfig, oObjectStore.Path) - ' TODO: - ' - Get Object Store -> Object Catalog -> Catalog Path - ' - If IS_ARCHIVE = True And RetentionDays <> Nothing: - ' DoArchive! - ' - Refactor EDMIPath to get ObjectStore at service start up - ' and return ObjectStore Path from ObjectStoreId + RelativePath - ' VWIDB_OBJECTSTORE + ' ' TODO: + ' ' - Get Object Store -> Object Catalog -> Catalog Path + ' ' - If IS_ARCHIVE = True And RetentionDays <> Nothing: + ' ' DoArchive! + ' ' - Refactor EDMIPath to get ObjectStore at service start up + ' ' and return ObjectStore Path from ObjectStoreId + RelativePath + ' ' VWIDB_OBJECTSTORE - Dim oRelativePath As String = EDMIPath.GetRelativePath(Data.DocumentType, Data.FileName) - Dim oAbsolutePath As String = EDMIPath.GetFullPath(Data.DocumentType, Data.FileName) - Dim oDirectoryPath = EDMIPath.GetFullPath(Data.DocumentType) + ' Dim oRelativePath As String = EDMIPath.GetRelativePath(Data.DocumentType, Data.FileName) + ' Dim oAbsolutePath As String = EDMIPath.GetFullPath(Data.DocumentType, Data.FileName) + ' Dim oDirectoryPath = EDMIPath.GetFullPath(Data.DocumentType) - Try - Directory.CreateDirectory(oDirectoryPath) + ' Try + ' Directory.CreateDirectory(oDirectoryPath) - Dim oVersionedFileName As String = Filesystem.GetVersionedFilename(oAbsolutePath) + ' Dim oVersionedFileName As String = Filesystem.GetVersionedFilename(oAbsolutePath) - _Logger.Info("ImportFile: Saving file [{0}] to path [{1}]", Data.FileName, oVersionedFileName) - Using oStream = New FileStream(oVersionedFileName, FileMode.CreateNew) - oStream.Write(Data.Contents, 0, Data.Contents.Length) - oStream.Flush(True) - oStream.Close() - End Using + ' _Logger.Info("ImportFile: Saving file [{0}] to path [{1}]", Data.FileName, oVersionedFileName) + ' Using oStream = New FileStream(oVersionedFileName, FileMode.CreateNew) + ' oStream.Write(Data.Contents, 0, Data.Contents.Length) + ' oStream.Flush(True) + ' oStream.Close() + ' End Using - ' insert into db - Dim oCommand As New SqlCommand("PRIDB_NEW_DOCUMENT") - oCommand.Parameters.AddWithValue("@OBJ_ST_ID", 1) - oCommand.Parameters.AddWithValue("@REL_PATH", oRelativePath) - oCommand.Parameters.AddWithValue("@WHO", _Username) - oCommand.Parameters.AddWithValue("@REF_DOCID", 0) - oCommand.Parameters.Add(New SqlParameter("@IDB_OBJ_ID", SqlDbType.BigInt)) + ' ' insert into db + ' Dim oCommand As New SqlCommand("PRIDB_NEW_DOCUMENT") + ' oCommand.Parameters.AddWithValue("@OBJ_ST_ID", 1) + ' oCommand.Parameters.AddWithValue("@REL_PATH", oRelativePath) + ' oCommand.Parameters.AddWithValue("@WHO", _Username) + ' oCommand.Parameters.AddWithValue("@REF_DOCID", 0) + ' oCommand.Parameters.Add(New SqlParameter("@IDB_OBJ_ID", SqlDbType.BigInt)) - Dim oObjectId = MSSQL_IDB.GetScalarValue(oCommand, "@IDB_OBJ_ID") + ' Dim oObjectId = MSSQL_IDB.GetScalarValue(oCommand, "@IDB_OBJ_ID") - Return New DocumentImportResponse() With {.ObjectId = oObjectId} + ' Return New DocumentImportResponse() With {.ObjectId = oObjectId} - Catch ex As FaultException - _Logger.Error(ex) - Throw ex + ' Catch ex As FaultException + ' _Logger.Error(ex) + ' Throw ex - Catch ex As Exception - _Logger.Error(ex) - Throw GetFault(ex) + ' Catch ex As Exception + ' _Logger.Error(ex) + ' Throw GetFault(ex) - End Try - End Function + ' End Try + 'End Function Public Function GetFileByObjectId(Data As DocumentStreamRequest) As DocumentStreamResponse Implements IEDMIService.GetFileByObjectId Try @@ -447,29 +542,6 @@ Public Class EDMIService End Try End Function - Public Function NewObjectId(Data As NewObjectIdRequest) As NewObjectIdResponse Implements IEDMIService.NewObjectId - Try - Dim oSQL As String = $"DECLARE @NEW_IDB_OBJ_ID BIGINT - EXEC PRIDB_NEW_OBJECT '{Data.KindType}','{Data.Who}','{Data.BusinessEntity}',0, @IDB_OBJ_ID = @NEW_IDB_OBJ_ID OUTPUT; - SELECT @NEW_IDB_OBJ_ID" - Dim oObjectId = MSSQL_IDB.GetScalarValue(oSQL) - - If oObjectId Is Nothing Then - Throw GetFault("NewObjectId: Could not create new ObjectId!") - End If - - Return New NewObjectIdResponse With {.ObjectId = oObjectId} - Catch ex As FaultException - _Logger.Error(ex) - Throw ex - - Catch ex As Exception - _Logger.Error(ex) - Throw GetFault(ex) - - End Try - End Function - Public Function TestObjectIdExists(Data As TestObjectIdExistsRequest) As TestObjectIdExistsResponse Implements IEDMIService.TestObjectIdExists Try Dim oSQL As String = $"SELECT IDB_OBJ_ID, ACTIVE, DELETED FROM TBIDB_OBJECT WHERE IDB_OBJ_ID = {Data.ObjectId}" @@ -496,119 +568,20 @@ Public Class EDMIService End Try End Function - Public Function NewFileObject(Data As NewFileObjectRequest) As NewFileObjectResponse Implements IEDMIService.NewFileObject - Try - Dim oStoreType As String = Data.StoreType - _Logger.Debug("DataStore type is [{0}]", oStoreType) - If oStoreType = String.Empty Then - _Logger.Debug("DataStore empty, set to [{0}]", ClassConstants.FileStoreWork) - oStoreType = ClassConstants.FileStoreWork - End If - Dim oBasePath As String = GetFileStorePraefix(oStoreType) - Dim oSubDirectory As String - - If IsNothing(Data.DateImported) Then - oSubDirectory = GetDateSubDirectory(Now) - Else - oSubDirectory = GetDateSubDirectory(Data.DateImported) - End If - - _Logger.Debug("Subdirectory is [{0}]", oSubDirectory) - - Dim oFinalPath = Path.Combine(oBasePath, oSubDirectory) - - If Not Directory.Exists(oFinalPath) Then - Try - _Logger.Debug("Path does not exist, creating: [{0}]", oFinalPath) - Directory.CreateDirectory(oFinalPath) - _Logger.Debug("Created folder [{0}]", oFinalPath) - Catch ex As Exception - Throw GetFault(ex) - End Try - End If - - _Logger.Debug("Final Directory is [{0}]", oFinalPath) - - Dim oFileName As String = GetFileObjectFileName(Data.ObjectId, Data.Extension, Data.KeepExtension) - - Dim oFileObjectPath As String = Path.Combine(oFinalPath, oFileName) - _Logger.Debug("Final Path is [{0}]", oFileObjectPath) - - Return New NewFileObjectResponse With {.FileObjectPath = oFileObjectPath} - Catch ex As FaultException - _Logger.Error(ex) - Throw ex - - Catch ex As Exception - _Logger.Error(ex) - Throw GetFault(ex) - - End Try - End Function - - Public Function ImportFileIntoFileObject(Data As ImportFileIntoFileObjectRequest) As ImportFileIntoFileObjectResponse Implements IEDMIService.ImportFileIntoFileObject - Try - Dim oObjectStore = GlobalState.GetObjectStore(Data.ObjectStoreType) - If oObjectStore Is Nothing Then - Throw New KeyNotFoundException($"ObjectStore [{Data.ObjectStoreType}] was not found.") - End If - - Using oStream = New FileStream(Data.FilePath, FileMode.Create, FileAccess.Write) - _Logger.Info("ImportFile: Saving file to path [{0}]", Data.FilePath) - _Logger.Info("ImportFile: Content Length: {0}", Data.Contents.Length) - - oStream.Write(Data.Contents, 0, Data.Contents.Length) - oStream.Flush(True) - oStream.Close() - End Using - - ' Insert into DB - Dim oSQL As String = $"EXEC PRIDB_NEW_IDBFO '{Data.FilePath}',{Data.Contents.Length},'{Data.Who}','{Data.ObjectId}',{oObjectStore.Id}" - Dim oResult As Boolean = MSSQL_IDB.ExecuteNonQuery(oSQL) - - Return New ImportFileIntoFileObjectResponse() With {.Result = oResult} - - Catch ex As FaultException - _Logger.Error(ex) - Throw ex - - Catch ex As Exception - _Logger.Error(ex) - Throw GetFault(ex) - - End Try - End Function #End Region #Region "=== Private ===" - Private Function GetFileObjectFileName(IDB_OBJ_ID As Long, pExtension As String, pKeepExtension As Boolean) As String - If Not pExtension.StartsWith("."c) Then - pExtension &= "."c - End If - - If pKeepExtension Then - Return $"{IDB_OBJ_ID}{pExtension}" + Private Function GetFileObjectFileName(IDB_OBJ_ID As Long, pFilename As String, pKeepFilename As Boolean) As String + If pKeepFilename Then + Return pFilename Else Return $"{IDB_OBJ_ID}.ddfo" End If End Function - Private Function GetFileStorePraefix(pStoreType As String) As String - Dim oObjectStore - - If pStoreType = ClassConstants.FileStoreArchive Then - oObjectStore = GlobalState.ObjectStores.Item(0) - Else ' pStoreType = ClassConstants.FileStoreWork Then - oObjectStore = GlobalState.ObjectStores.Item(1) - End If - - _Logger.Debug($"oObjectStore is [{oObjectStore.Path}]") - Return oObjectStore.Path - End Function - Private Function GetDateSubDirectory(pDate As Date) As String Return Path.Combine(pDate.ToString("yyyy"), pDate.ToString("MM"), pDate.ToString("dd")) End Function @@ -690,6 +663,21 @@ Public Class EDMIService Return AccessRight.VIEW_ONLY End Try End Function + + Private Function StripDomainFromUsername(UserName As String) + If UserName.Contains("\") Then + Return UserName.Split("\")(1) + ElseIf UserName.Contains("@") Then + Return UserName.Split("@")(0) + Else + Return UserName + End If + End Function + + Private Function LogAndThrow(pMessage As String) + _Logger.Warn(pMessage) + Throw New ApplicationException(pMessage) + End Function #End Region diff --git a/Service.EDMIService/EDMIService.vbproj b/Service.EDMIService/EDMIService.vbproj index a407f6bd..786f0875 100644 --- a/Service.EDMIService/EDMIService.vbproj +++ b/Service.EDMIService/EDMIService.vbproj @@ -129,10 +129,12 @@ + + - + diff --git a/Service.EDMIService/Filestorage/NewFile/NewFileRequest.vb b/Service.EDMIService/Filestorage/NewFile/NewFileRequest.vb new file mode 100644 index 00000000..39002b47 --- /dev/null +++ b/Service.EDMIService/Filestorage/NewFile/NewFileRequest.vb @@ -0,0 +1,69 @@ +Imports System.Runtime.Serialization + +Namespace FileStorage.NewFile + + + Public Class NewFileRequest + ''' + ''' Absolute filename of the file to be imported + ''' + + Public Property FileName As String + + ''' + ''' Creation date of the original file from the filesystem + ''' + + Public Property FileCreatedAt As String + + ''' + ''' Modification date of the original file from the filesystem + ''' + + Public Property FileChangedAt As String + + ''' + ''' Date for which the file should be show as imported + ''' + + Public Property FileImportedAt As Date + + ''' + ''' The byte array representing the file contents + ''' + + Public Property FileContents As Byte() + + ''' + ''' The SHA256 Hash of the file contents + ''' + + Public Property FileChecksum As String + + ''' + ''' Name/title of the ObjectStore to save the file to, ex. Work + ''' + + Public Property StoreName As String + + ''' + ''' The business entity of the file, ex DEFAULT + ''' + + Public Property BusinessEntity As String + + ''' + ''' The kind of object to be created, ex. DOC + ''' + + Public Property KindType As String + + ''' + ''' The name of the user importing the file, ex. JenneJ + ''' + + Public Property Who As String + End Class + +End Namespace + diff --git a/Service.EDMIService/Filestorage/NewFile/NewFileResponse.vb b/Service.EDMIService/Filestorage/NewFile/NewFileResponse.vb new file mode 100644 index 00000000..20a0e28e --- /dev/null +++ b/Service.EDMIService/Filestorage/NewFile/NewFileResponse.vb @@ -0,0 +1,22 @@ +Imports System.Runtime.Serialization + +Namespace FileStorage.NewFile + + + Public Class NewFileResponse + Inherits Messages.BaseResponse + + + Public Property ObjectId As Long + + Public Sub New(pObjectId As Long) + MyBase.New() + ObjectId = pObjectId + End Sub + + Public Sub New(pException As Exception) + MyBase.New(pException) + End Sub + End Class + +End Namespace diff --git a/Service.EDMIService/Helpers/AccessRightResult.vb b/Service.EDMIService/Helpers/AccessRightResult.vb index d38239ff..128df386 100644 --- a/Service.EDMIService/Helpers/AccessRightResult.vb +++ b/Service.EDMIService/Helpers/AccessRightResult.vb @@ -6,7 +6,7 @@ Namespace Messages Public Class AccessRightResult - Inherits BaseResult + Inherits BaseResponse Public Property Right As AccessRight = AccessRight.VIEW_ONLY diff --git a/Service.EDMIService/Helpers/BaseResult.vb b/Service.EDMIService/Helpers/BaseResponse.vb similarity index 93% rename from Service.EDMIService/Helpers/BaseResult.vb rename to Service.EDMIService/Helpers/BaseResponse.vb index 72cfd738..e8b3d075 100644 --- a/Service.EDMIService/Helpers/BaseResult.vb +++ b/Service.EDMIService/Helpers/BaseResponse.vb @@ -4,7 +4,7 @@ Namespace Messages - Public MustInherit Class BaseResult + Public MustInherit Class BaseResponse Public Property OK As Boolean diff --git a/Service.EDMIService/Helpers/DatabaseResult.vb b/Service.EDMIService/Helpers/DatabaseResult.vb index 63e006d0..8433cb55 100644 --- a/Service.EDMIService/Helpers/DatabaseResult.vb +++ b/Service.EDMIService/Helpers/DatabaseResult.vb @@ -6,7 +6,7 @@ Namespace Messages Public Class TableResult - Inherits BaseResult + Inherits BaseResponse Public Property Table As DataTable @@ -25,7 +25,7 @@ Namespace Messages Public Class ScalarResult - Inherits BaseResult + Inherits BaseResponse Public Property Scalar As Object @@ -44,7 +44,7 @@ Namespace Messages Public Class NonQueryResult - Inherits BaseResult + Inherits BaseResponse Public Sub New() MyBase.New() diff --git a/Service.EDMIService/Helpers/Messages.vb b/Service.EDMIService/Helpers/Messages.vb index 9d85f186..943133d2 100644 --- a/Service.EDMIService/Helpers/Messages.vb +++ b/Service.EDMIService/Helpers/Messages.vb @@ -26,64 +26,6 @@ Namespace Messages Public ObjectId As Long End Class #End Region -#Region "FileImport 2021" - - Public Class ImportFileIntoFileObjectRequest - - Public Contents() As Byte - - Public Who As String - - Public FilePath As String - - Public ObjectId As Long - - Public ObjectStoreType As String - End Class - - - Public Class ImportFileIntoFileObjectResponse - - Public Result As Boolean - End Class - - - Public Class NewObjectIdRequest - - Public KindType As String - - Public Who As String - - Public BusinessEntity As String - End Class - - - Public Class NewObjectIdResponse - - Public ObjectId As Long - End Class - - - Public Class NewFileObjectRequest - - Public ObjectId As Long - - Public StoreType As String - - Public DateImported As Date - - Public Extension As String - - Public KeepExtension As Boolean - End Class - - - Public Class NewFileObjectResponse - - Public FileObjectPath As String - End Class - -#End Region #Region "DocumentStream" diff --git a/Service.EDMIService/IEDMIService.vb b/Service.EDMIService/IEDMIService.vb index 606fed9a..a58f8933 100644 --- a/Service.EDMIService/IEDMIService.vb +++ b/Service.EDMIService/IEDMIService.vb @@ -3,6 +3,7 @@ Imports System.ServiceModel Imports DigitalData.Modules.Filesystem Imports DigitalData.Services.EDMIService.Exceptions Imports DigitalData.Services.EDMIService.Messages +Imports DigitalData.Services.EDMIService.FileStorage Interface IEDMIService @@ -63,8 +64,11 @@ Interface IEDMIService #Region "Document (New)" - - Function ImportFile(Data As DocumentImportRequest) As DocumentImportResponse + Function NewFile(Data As NewFile.NewFileRequest) As NewFile.NewFileResponse + + '----------------------------------------------------- + ' Everything below this line is subject to change! + '----------------------------------------------------- @@ -79,17 +83,7 @@ Interface IEDMIService Function ListFilesForUser() As DocumentListResponse - - - Function NewObjectId(Data As NewObjectIdRequest) As NewObjectIdResponse - - - Function NewFileObject(Data As NewFileObjectRequest) As NewFileObjectResponse - - - - Function ImportFileIntoFileObject(Data As ImportFileIntoFileObjectRequest) As ImportFileIntoFileObjectResponse #End Region #Region "Helpers" diff --git a/Service.EDMIService/Scheduler/DatatableJob.vb b/Service.EDMIService/Scheduler/DatatableJob.vb index 934ffffa..b0c01c96 100644 --- a/Service.EDMIService/Scheduler/DatatableJob.vb +++ b/Service.EDMIService/Scheduler/DatatableJob.vb @@ -44,8 +44,9 @@ Public Class DatatableJob oLogger.Debug("Connection Id: {0}", oConnectionId) Dim oConnectionString = oMSSQL.Get_ConnectionStringforID(oConnectionId) + Dim oDecryptedConnectionString = MSSQLServer.DecryptConnectionString(oConnectionString) - Dim oTable = oMSSQL.GetDatatableWithConnection(oSQL, oConnectionString, COMMAND_SQL_TIMEOUT) + Dim oTable = oMSSQL.GetDatatableWithConnection(oSQL, oDecryptedConnectionString, COMMAND_SQL_TIMEOUT) oTable.TableName = oDatatableName Dim oView As DataView = Nothing