Monorepo/Service.EDMIService/EDMIService.vb

646 lines
25 KiB
VB.net

Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports DigitalData.Modules
Imports System.IO
Imports System.ServiceModel
Imports System.Data.SqlClient
Imports System.ServiceModel.Description
Imports DigitalData.Services.EDMIService.Messages
Imports DigitalData.Modules.EDMI.API.Rights
Imports DigitalData.Services.EDMIService.Exceptions
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession)>
Public Class EDMIService
Implements IEDMIService
Public Shared LogConfig As LogConfig
Public Shared MSSQL_ECM As MSSQLServer
Public Shared MSSQL_IDB As MSSQLServer
Public Shared Firebird As Firebird
Public Shared AppConfig As Config
Public Shared Filesystem As Filesystem.File
Public Shared EDMIArchive As EDMI.File.Archive
Public Shared GlobalState As GlobalState
Public Shared Scheduler As Scheduler
Public Const TBIDB_DOC_INFO = "TBIDB_DOC_INFO"
Public Const TBIDB_ACCESSRIGHT = "TBIDB_ACCESSRIGHT"
Private ReadOnly _Logger As Logger
Private ReadOnly _Debug As Boolean = False
Private ReadOnly _Username As String
Public Shared Sub Configure(Config As ServiceConfiguration)
Dim oBaseAddress = Config.BaseAddresses.Item(0)
Dim oBinding = EDMI.API.Channel.GetBinding()
Dim oAddress = New EndpointAddress(oBaseAddress)
' See: https://stackoverflow.com/questions/42327988/addserviceendpoint-throws-key-is-null
Dim oDescription = ContractDescription.GetContract(GetType(IEDMIService), GetType(EDMIService))
Dim oEndpoint As New ServiceEndpoint(oDescription, oBinding, oAddress)
Config.AddServiceEndpoint(oEndpoint)
Config.Description.Behaviors.Add(New ServiceDebugBehavior With {.IncludeExceptionDetailInFaults = True})
End Sub
Public Sub New()
Dim oOperationContext As OperationContext = OperationContext.Current
Dim oInstanceContext As InstanceContext = oOperationContext.InstanceContext
Dim oUsername = StripDomainFromUsername(oOperationContext.ServiceSecurityContext.WindowsIdentity.Name)
_Username = oUsername
_Logger = LogConfig.GetLogger()
_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
End Function
#Region "=== Heartbeat ==="
Public Function Heartbeat() As Boolean Implements IEDMIService.Heartbeat
Return True
End Function
#End Region
#Region "=== Database ==="
Public Function ReturnDatatableFromCache(Name As String, FilterExpression As String, SortByColumn As String) As TableResult Implements IEDMIService.ReturnDatatableFromCache
Try
_Logger.Info($"ReturnDatatableFromCache, Datatable: {Name}")
Dim oDataset As DataSet = GlobalState.TableStore
Dim oDataTable As DataTable = Nothing
_Logger.Debug("DataSet contains [{0}] datatables", oDataset.Tables.Count)
If oDataset.Tables.Contains(Name) Then
oDataTable = oDataset.Tables.Item(Name).Copy()
' Apply filter and sorting to data
Dim oFilterExpression As String = Utils.NotNull(FilterExpression, String.Empty)
Dim oSortByColumn As String = Utils.NotNull(SortByColumn, String.Empty)
Dim oFilteredRows = oDataTable.Select(oFilterExpression, oSortByColumn)
Dim oFilteredTable As DataTable = Nothing
If oFilteredRows.Count > 0 Then
oFilteredTable = oFilteredRows.CopyToDataTable()
oFilteredTable.TableName = Name
Else
' Produce empty table
oFilteredTable = oDataTable.Clone()
oFilteredTable.TableName = Name
End If
_Logger.Debug("Datatable Stats for [{0}]:", Name)
_Logger.Debug("Unfiltered: [{0}] rows", oDataTable.Rows.Count)
_Logger.Debug("Filtered: [{0}] rows", oFilteredTable.Rows.Count)
Return New TableResult(oFilteredTable)
Else
_Logger.Warn($"Datatable {Name} does not exist")
Dim oDetails As New DataTableDoesNotExistFault(Name)
Throw New FaultException(Of DataTableDoesNotExistFault)(oDetails)
End If
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
#End Region
#Region "=== Database (MSSQL IDB) ==="
Public Function ReturnDatatable_MSSQL_IDB(SQL As String) As TableResult Implements IEDMIService.ReturnDatatable_MSSQL_IDB
Try
_Logger.Info($"ReturnDatatable_MSSQL_IDB, SQL: {SQL}")
Dim oResult As DataTable = MSSQL_IDB.GetDatatable(SQL)
oResult.TableName = "DD_RESULT"
Return New TableResult(oResult)
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ReturnScalar_MSSQL_IDB(SQL As String) As ScalarResult Implements IEDMIService.ReturnScalar_MSSQL_IDB
Try
_Logger.Info($"ReturnScalar_MSSQL_IDB, SQL: {SQL}")
Dim oResult As Object = MSSQL_IDB.GetScalarValue(SQL)
Return New ScalarResult(oResult)
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ExecuteNonQuery_MSSQL_IDB(SQL As String) As NonQueryResult Implements IEDMIService.ExecuteNonQuery_MSSQL_IDB
Try
_Logger.Info($"ExecuteNonQuery_MSSQL_IDB, SQL: {SQL}")
Dim oResult As Boolean = MSSQL_IDB.ExecuteNonQuery(SQL)
Return New NonQueryResult()
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
#End Region
#Region "=== Database (MSSQL ECM) ==="
Public Function ReturnDatatable_MSSQL_ECM(SQL As String) As TableResult Implements IEDMIService.ReturnDatatable_MSSQL_ECM
Try
_Logger.Info($"ReturnDatatable_MSSQL_ECM, SQL: {SQL}")
Dim oResult As DataTable = MSSQL_ECM.GetDatatable(SQL)
oResult.TableName = "DD_RESULT"
Return New TableResult(oResult)
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ReturnScalar_MSSQL_ECM(SQL As String) As ScalarResult Implements IEDMIService.ReturnScalar_MSSQL_ECM
Try
_Logger.Info($"ReturnScalar_MSSQL_ECM, SQL: {SQL}")
Dim oResult As Object = MSSQL_ECM.GetScalarValue(SQL)
Return New ScalarResult(oResult)
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ExecuteNonQuery_MSSQL_ECM(SQL As String) As NonQueryResult Implements IEDMIService.ExecuteNonQuery_MSSQL_ECM
Try
_Logger.Info($"ExecuteNonQuery_MSSQL_ECM, SQL: {SQL}")
Dim oResult As Boolean = MSSQL_ECM.ExecuteNonQuery(SQL)
Return New NonQueryResult()
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
#End Region
#Region "=== Database (Firebird) ==="
Public Function ReturnDatatable_Firebird(SQL As String) As TableResult Implements IEDMIService.ReturnDatatable_Firebird
Try
_Logger.Info($"ReturnDatatable, SQL: {SQL}")
Dim oResult As DataTable = Firebird.GetDatatable(SQL)
oResult.TableName = "DD_RESULT"
Return New TableResult(oResult)
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ReturnScalar_Firebird(SQL As String) As ScalarResult Implements IEDMIService.ReturnScalar_Firebird
Try
_Logger.Info($"ReturnScalar, SQL: {SQL}")
Dim oResult As Object = Firebird.GetScalarValue(SQL)
Return New ScalarResult(oResult)
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ExecuteNonQuery_Firebird(SQL As String) As NonQueryResult Implements IEDMIService.ExecuteNonQuery_Firebird
Try
_Logger.Info($"ExecuteNonQuery, SQL: {SQL}")
Dim oResult As Boolean = Firebird.ExecuteNonQuery(SQL)
Return New NonQueryResult()
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
#End Region
#Region "=== Document ==="
''' <summary>
''' Imports a file according to ObjectStoreId
''' </summary>
''' <returns></returns>
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
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)
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
' 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")
Return New DocumentImportResponse() With {.ObjectId = oObjectId}
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function GetFileByObjectId(Data As DocumentStreamRequest) As DocumentStreamResponse Implements IEDMIService.GetFileByObjectId
Try
Dim oFullPath = GetFullPathForObjectId(Data.ObjectId)
If oFullPath = String.Empty Then
Dim oDetails As New ObjectDoesNotExistFault(Data.ObjectId)
_Logger.Warn("GetFileByObjectId: " & oDetails.ErrorMessage)
Throw New FaultException(Of ObjectDoesNotExistFault)(oDetails, oDetails.ErrorMessage)
End If
_Logger.Debug("GetFileByObjectId: Loading file [{0}]", oFullPath)
Dim oFileInfo As New FileInfo(oFullPath)
If Not oFileInfo.Exists Then
Dim oDetails As New ObjectDoesNotExistFault(Data.ObjectId)
_Logger.Warn("GetFileByObjectId: " & oDetails.ErrorMessage)
Throw New FaultException(Of ObjectDoesNotExistFault)(oDetails, oDetails.ErrorMessage)
End If
Dim oDestination As New MemoryStream()
Using oSource As FileStream = IO.File.OpenRead(oFullPath)
oSource.CopyTo(oDestination)
End Using
oDestination.Seek(0, SeekOrigin.Begin)
Dim oMessage As New DocumentStreamResponse() With {
.FileName = oFileInfo.Name,
.FileContents = oDestination
}
Return oMessage
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function GetFileInfoByObjectId(Data As DocumentInfoRequest) As DocumentInfoResponse Implements IEDMIService.GetFileInfoByObjectId
Try
Dim oAccessRight = GetAccessRightForObjectId(Data.UserId, Data.ObjectId)
Dim oFullPath = GetFullPathForObjectId(Data.ObjectId)
If oFullPath = String.Empty Then
Dim oFault As New ObjectDoesNotExistFault(Data.ObjectId)
Throw New FaultException(Of ObjectDoesNotExistFault)(oFault, oFault.ErrorMessage)
End If
Return New DocumentInfoResponse With {
.FileRight = oAccessRight,
.FullPath = oFullPath
}
Catch ex As FaultException
_Logger.Warn("GetFileInfoByObjectId: " & ex.Message)
_Logger.Error(ex)
Throw ex
Catch ex As Exception
Dim oDetails As New UnexpectedErrorFault(ex)
_Logger.Warn("GetFileInfoByObjectId: " & oDetails.ErrorMessage)
_Logger.Error(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function ListFilesForUser() As DocumentListResponse Implements IEDMIService.ListFilesForUser
Try
Dim oDatatable = GetFileList()
Return New DocumentListResponse() With {
.Datatable = oDatatable
}
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Public Function GetFileList() As DataTable
Try
If Not GlobalState.TableStore.Tables.Contains(TBIDB_DOC_INFO) Then
_Logger.Warn("GetFileList: Document info table does not exist!")
Return Nothing
End If
Dim oTable As DataTable = GlobalState.TableStore.Tables.Item(TBIDB_DOC_INFO)
Return oTable
Catch ex As Exception
_Logger.Warn("GetFileList: Unexpected Error while getting file list.")
_Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function GetFullPathForObjectId(ObjectId As Long) As String
Try
If Not GlobalState.TableStore.Tables.Contains(TBIDB_DOC_INFO) Then
_Logger.Warn("GetFullPathForObjectId: Document info table does not exist!")
Return String.Empty
End If
Dim oTable As DataTable = GlobalState.TableStore.Tables.Item(TBIDB_DOC_INFO)
Dim oRows As List(Of DataRow) = oTable.Select($"IDB_OBJ_ID = {ObjectId}").ToList()
Dim oFullPath As String
If oRows.Count = 0 Then
_Logger.Warn("GetFullPathForObjectId: Full path does not exist for object [{0}]", ObjectId)
oFullPath = String.Empty
Else
Dim oRow As DataRow = oRows.First()
oFullPath = oRow.Item("FULL_PATH")
End If
Return oFullPath
Catch ex As Exception
_Logger.Warn("GetFullPathForObjectId: Unexpected Error while getting full path for object [{0}].", ObjectId)
_Logger.Error(ex)
Return String.Empty
End Try
End Function
Private Function GetAccessRightForObjectId(UserId As Long, ObjectId As Long) As AccessRight
Try
If Not GlobalState.TableStore.Tables.Contains(TBIDB_ACCESSRIGHT) Then
_Logger.Warn("GetAccessRightForObjectId: Access right table does not exist!")
Return AccessRight.VIEW_ONLY
End If
Dim oTable As DataTable = GlobalState.TableStore.Tables.Item(TBIDB_ACCESSRIGHT)
Dim oRows As List(Of DataRow) = oTable.Select($"IDB_OBJ_ID = {ObjectId} AND USR_ID = {UserId}").ToList()
Dim oRight As AccessRight
If oRows.Count = 0 Then
_Logger.Warn("GetAccessRightForObjectId: Access right assignment does not exist for user [{0}] on object [{1}]", UserId, ObjectId)
Return AccessRight.VIEW_ONLY
Else
If oRows.Count > 1 Then
_Logger.Warn("GetAccessRightForObjectId: More than one access right assignment found for user [{0}] on object [{1}]", UserId, ObjectId)
End If
Dim oRow As DataRow = oRows.First()
Dim oRightAsInt = oRow.Item("ACCESSRIGHT")
oRight = Utils.ToEnum(Of AccessRight)(oRightAsInt)
End If
Return oRight
Catch ex As Exception
_Logger.Warn("GetAccessRightForObjectId: Unexpected Error while getting access right for object [{0}].", ObjectId)
_Logger.Error(ex)
Return AccessRight.VIEW_ONLY
End Try
End Function
Public Function New_FileStore_Object(IDB_OBJ_ID As Long, pStoreType As String, pDate As String) As String Implements IEDMIService.New_FileStore_Object
Try
Dim oRelpath As String
If pStoreType = String.Empty Then
pStoreType = ClassConstants.FileStoreWork
End If
oRelpath = GetFileStorePraefix(pStoreType)
If pDate = String.Empty Then
oRelpath = GetFolderToday(oRelpath)
Else
Try
Dim odate = CDate(pDate)
oRelpath = GetFolderDate(oRelpath, odate)
Catch ex As Exception
Return ""
End Try
End If
Dim oIDB_FileObject As String
If oRelpath = String.Empty Then
Return "ERROR"
Else
_Logger.Debug($"oRelpath is [{oRelpath}]")
oIDB_FileObject = Path.Combine(oRelpath, GetDigitalDataFileObject(IDB_OBJ_ID))
End If
Return oIDB_FileObject
Catch ex As Exception
_Logger.Error(ex)
Return ""
End Try
End Function
Public Function NewIDB_Object(pKindType As String, pWho As String, pBusinessEntity As String) As String Implements IEDMIService.New_IDB_OBJECT
Try
Dim oSQL As String = $"DECLARE @NEW_IDB_OBJ_ID BIGINT
EXEC PRIDB_NEW_OBJECT '{pKindType}','{pWho}','{pBusinessEntity}',0, @IDB_OBJ_ID = @NEW_IDB_OBJ_ID OUTPUT;
SELECT @NEW_IDB_OBJ_ID"
Dim oObjectId = MSSQL_IDB.GetScalarValue(oSQL)
Return oObjectId
Catch ex As Exception
_Logger.Error(ex)
Return 0
End Try
End Function
Public Function ImportFileIDBFO(Data As DocumentImportIDBFORequest) As DocumentImportIDBFOResponse Implements IEDMIService.ImportNewIDBFO
Dim oObjectStore = GlobalState.ObjectStores.First()
Dim EDMIPath = New EDMI.File.Path(LogConfig, oObjectStore.Path)
Try
_Logger.Info("ImportFile: Saving file to path [{0}]", Data.pIDBFilePath)
Using oStream = New FileStream(Data.pIDBFilePath, FileMode.CreateNew)
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.pIDBFilePath}','{Data.pWho}','{Data.pIDB_OBJ_ID}',{Data.pObjectStoreID}"
Dim oResult As Boolean = MSSQL_IDB.ExecuteNonQuery(oSQL)
Return New DocumentImportIDBFOResponse() With {.Result = oResult}
Catch ex As FaultException
_Logger.Error(ex)
Throw ex
Catch ex As Exception
_Logger.Error(ex)
Dim oDetails As New UnexpectedErrorFault(ex)
Throw New FaultException(Of UnexpectedErrorFault)(oDetails, oDetails.ErrorMessage)
End Try
End Function
Private Function GetDigitalDataFileObject(IDB_OBJ_ID As Long) As String
Return $"{IDB_OBJ_ID}.ddfo"
End Function
Private Function GetFileStorePraefix(pStoreType As String) As String
Dim oObjectStore
Dim EDMIPath As String
If pStoreType = ClassConstants.FileStoreArchive Then
oObjectStore = GlobalState.ObjectStores.Item(0)
Else pStoreType = ClassConstants.FileStoreWork
oObjectStore = GlobalState.ObjectStores.Item(1)
End If
_Logger.Debug($"oObjectStore is [{oObjectStore.Path}]")
Return oObjectStore.Path
End Function
Private Function GetFolderToday(pRelationalPath As String) As String
Dim oDateSubDirectoryName As String = Now.ToString("yyyy-MM-dd")
Dim oFolderToday As String = Path.Combine(pRelationalPath, oDateSubDirectoryName)
' Create the destination directory if it does not exist
If Not Directory.Exists(oFolderToday) Then
Try
Directory.CreateDirectory(oFolderToday)
_Logger.Debug($"created NEW todayFolder [{oFolderToday}]")
Catch ex As Exception
_Logger.Error(ex)
Return ""
End Try
End If
Return oFolderToday
End Function
Private Function GetFolderDate(pRelationalPath As String, pDate As Date) As String
Dim oDateSubDirectoryName As String = pDate.ToString("yyyy-MM-dd")
Dim oFolderDateSepecial As String = Path.Combine(pRelationalPath, oDateSubDirectoryName)
' Create the destination directory if it does not exist
If Not Directory.Exists(oFolderDateSepecial) Then
Try
Directory.CreateDirectory(oFolderDateSepecial)
_Logger.Debug($"created NEW DateSpecialFolder [{oFolderDateSepecial}]")
Catch ex As Exception
_Logger.Error(ex)
Return ""
End Try
End If
Return oFolderDateSepecial
End Function
#End Region
End Class