Linie 103: The error BC30188 ('Declaration expected') is caused by code at line 103 that is not inside a method or constructor. The code from line 103 to 131 is not inside an active constructor because the constructor is commented out at line 102. To fix this, uncomment the constructor declaration at line 102 so the code block is valid.
Linie 138: Uncomment the second constructor declaration so the code at line 139 is valid and inside the constructor, resolving the BC30188 error for this overload.“ in Datei „Config\ConfigManager.vb“
358 lines
13 KiB
VB.net
358 lines
13 KiB
VB.net
Imports System.IO
|
|
Imports System.Reflection
|
|
Imports System.Xml.Serialization
|
|
Imports DigitalData.Modules.Config
|
|
|
|
Public Class ConfigManager(Of T)
|
|
Public Const USER_CONFIG_NAME As String = "UserConfig.xml"
|
|
Public Const COMPUTER_CONFIG_NAME As String = "ComputerConfig.xml"
|
|
Public Const APP_CONFIG_NAME As String = "AppConfig.xml"
|
|
|
|
' Private ReadOnly _LogConfig As LogConfig
|
|
Private ReadOnly _Logger As Logger
|
|
Private ReadOnly _File As FilesystemEx
|
|
|
|
Private ReadOnly _UserDirectory As String
|
|
Private ReadOnly _UserConfigPath As String
|
|
Private ReadOnly _ComputerDirectory As String
|
|
Private ReadOnly _ComputerConfigPath As String
|
|
Private ReadOnly _AppConfigDirectory As String
|
|
Private ReadOnly _AppConfigPath As String
|
|
|
|
Private ReadOnly _TestMode As Boolean = False
|
|
|
|
Private ReadOnly _Blueprint As T
|
|
Private ReadOnly _BlueprintType As Type
|
|
Private ReadOnly _Serializer As XmlSerializer
|
|
|
|
Private ReadOnly _ExcludedAttributes = New List(Of Type) From {
|
|
GetType(ConnectionStringAttribute),
|
|
GetType(ConnectionStringAppServerAttribute),
|
|
GetType(ConnectionStringTestAttribute),
|
|
GetType(EDMIAppServerAttribute),
|
|
GetType(GlobalSettingAttribute)
|
|
}
|
|
|
|
Private ReadOnly _ConnectionStringAttributes = New List(Of Type) From {
|
|
GetType(ConnectionStringAttribute),
|
|
GetType(ConnectionStringAppServerAttribute),
|
|
GetType(ConnectionStringTestAttribute)
|
|
}
|
|
|
|
''' <summary>
|
|
''' Signals that all properties will be written to (and read from) the UserConfig.xml
|
|
'''
|
|
''' If Value is `True`:
|
|
''' - AppConfig.xml does NOT exist
|
|
''' - ComputerConfig.xml does NOT exist
|
|
''' - ConnectionStrings will be saved to or read from UserConfig.xml
|
|
'''
|
|
''' If Value is `False`:
|
|
''' - No ConnectionStrings will be saved to or read from UserConfig.xml
|
|
'''
|
|
''' Can be overwritten by optional parameter `ForceUserConfig`
|
|
''' </summary>
|
|
Private _WriteAllValuesToUserConfig As Boolean = False
|
|
|
|
''' <summary>
|
|
''' Returns the currently loaded config object
|
|
''' </summary>
|
|
''' <returns></returns>
|
|
Public ReadOnly Property Config As T
|
|
|
|
''' <summary>
|
|
''' Path to the current user config.
|
|
''' </summary>
|
|
''' <returns></returns>
|
|
Public ReadOnly Property UserConfigPath As String
|
|
Get
|
|
Return _UserConfigPath
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Path to the current computer config.
|
|
''' </summary>
|
|
''' <returns></returns>
|
|
Public ReadOnly Property ComputerConfigPath As String
|
|
Get
|
|
Return _ComputerConfigPath
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Path to the current Application config.
|
|
''' </summary>
|
|
''' <returns></returns>
|
|
Public ReadOnly Property AppConfigPath As String
|
|
Get
|
|
Return _AppConfigPath
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Creates a new instance of the ConfigManager
|
|
''' </summary>
|
|
''' <seealso cref="ConfigSample"/>
|
|
''' <param name="LogConfig">LogConfig instance</param>
|
|
''' <param name="UserConfigPath">The path to check for a user config file, eg. AppData (Usually Application.UserAppDataPath or Application.LocalUserAppDataPath)</param>
|
|
''' <param name="ComputerConfigPath">The path to check for a computer config file, eg. ProgramData (Usually Application.CommonAppDataPath)</param>
|
|
''' <param name="ApplicationStartupPath">The path to check for a third config file. This is useful when running the Application in an environment where AppData/ProgramData directories are not available</param>
|
|
''' <param name="ForceUserConfig">Override values from ComputerConfig with UserConfig</param>
|
|
Public Sub New(LogConfig As LogConfig, UserConfigPath As String, ComputerConfigPath As String, Optional ApplicationStartupPath As String = "", Optional ForceUserConfig As Boolean = False)
|
|
|
|
''' <summary>
|
|
''' Creates a new ConfigManager with a single (user)config path
|
|
''' </summary>
|
|
''' <param name="LogConfig">LogConfig instance</param>
|
|
''' <param name="ConfigPath">The path to check for a user config file, eg. AppData (Usually Application.UserAppDataPath or Application.LocalUserAppDataPath)</param>
|
|
Public Sub New(LogConfig As LogConfig, ConfigPath As String)
|
|
MyClass.New(LogConfig, ConfigPath, String.Empty, String.Empty, ForceUserConfig:=True)
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Save the current config object to `UserConfigPath`
|
|
''' </summary>
|
|
''' <param name="ForceAll">Force saving all attributes including the attributes marked as excluded</param>
|
|
''' <returns>True if save was successful, False otherwise</returns>
|
|
Public Function Save(Optional ForceAll As Boolean = False) As Boolean
|
|
Try
|
|
WriteToFile(Config, _UserConfigPath, ForceAll)
|
|
Return True
|
|
Catch ex As Exception
|
|
_Logger.Error(ex)
|
|
Return False
|
|
End Try
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Reloads the config object from file.
|
|
''' </summary>
|
|
''' <returns>True if reload was successful, False otherwise</returns>
|
|
Public Function Reload() As Boolean
|
|
Try
|
|
_Config = LoadConfig()
|
|
Return True
|
|
Catch ex As Exception
|
|
_Logger.Error(ex)
|
|
Return False
|
|
End Try
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Copies all properties from Source to Target, except those who have an attribute
|
|
''' listed in ExcludedAttributeTypes
|
|
''' </summary>
|
|
''' <param name="Source">Source config object</param>
|
|
''' <param name="Target">Target config object</param>
|
|
''' <param name="ExcludedAttributeTypes">List of Attribute type to exclude</param>
|
|
Private Sub CopyValues(Source As T, Target As T, Optional ExcludedAttributeTypes As List(Of Type) = Nothing)
|
|
Dim oType As Type = GetType(T)
|
|
Dim oExcludedAttributeTypes = IIf(IsNothing(ExcludedAttributeTypes), New List(Of Type), ExcludedAttributeTypes)
|
|
Dim oProperties = oType.GetProperties().
|
|
Where(Function(p) p.CanRead And p.CanWrite).
|
|
Where(Function(p)
|
|
For Each oAttributeType As Type In oExcludedAttributeTypes
|
|
If Attribute.IsDefined(p, oAttributeType) Then
|
|
Return False
|
|
End If
|
|
Next
|
|
Return True
|
|
End Function)
|
|
|
|
For Each oProperty As PropertyInfo In oProperties
|
|
' TODO: Process individual Subfields of class-objects
|
|
' to allow for the PasswordAttribute to be set on class properies aka nested properties
|
|
|
|
Dim oValue = oProperty.GetValue(Source, Nothing)
|
|
If Not IsNothing(oValue) Then
|
|
oProperty.SetValue(Target, oValue, Nothing)
|
|
End If
|
|
Next
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Filters a config object by copying all values except `ExcludedAttributeTypes`
|
|
''' </summary>
|
|
''' <param name="Data">Config object</param>
|
|
''' <param name="ExcludedAttributeTypes">List of Attribute type to exclude</param>
|
|
''' <returns></returns>
|
|
Private Function FilterValues(ByVal Data As T, ExcludedAttributeTypes As List(Of Type)) As T
|
|
Dim oResult As T = Activator.CreateInstance(Of T)
|
|
|
|
CopyValues(Data, oResult, ExcludedAttributeTypes)
|
|
Return oResult
|
|
End Function
|
|
|
|
Private Function LoadConfig() As T
|
|
' first create an empty/default config object
|
|
Dim oConfig As T = Activator.CreateInstance(_BlueprintType)
|
|
|
|
' try to load the special app config
|
|
oConfig = LoadAppConfig(oConfig)
|
|
|
|
' try to load the computer config
|
|
oConfig = LoadComputerConfig(oConfig)
|
|
|
|
' now try to load userconfig
|
|
oConfig = LoadUserConfig(oConfig)
|
|
Return oConfig
|
|
End Function
|
|
|
|
Private Function LoadAppConfig(ByVal Config As T) As T
|
|
If Not String.IsNullOrEmpty(_AppConfigPath) AndAlso File.Exists(_AppConfigPath) Then
|
|
Try
|
|
Dim oAppConfig = ReadFromFile(_AppConfigPath)
|
|
CopyValues(oAppConfig, Config)
|
|
|
|
_Logger.Info("AppConfig exists and will be used. [{0}]", _AppConfigPath)
|
|
Catch ex As Exception
|
|
_Logger.Error(ex)
|
|
_Logger.Warn("ApplicationConfig could not be loaded!")
|
|
End Try
|
|
|
|
_WriteAllValuesToUserConfig = False
|
|
Else
|
|
_Logger.Debug("ApplicationConfig does not exist.")
|
|
_WriteAllValuesToUserConfig = True
|
|
End If
|
|
|
|
Return Config
|
|
End Function
|
|
|
|
Private Function LoadComputerConfig(ByVal Config As T) As T
|
|
If _WriteAllValuesToUserConfig = False Then
|
|
_Logger.Info("AppConfig exists. ComputerConfig will NOT be used")
|
|
ElseIf File.Exists(_ComputerConfigPath) Then
|
|
Try
|
|
Dim oComputerConfig = ReadFromFile(_ComputerConfigPath)
|
|
CopyValues(oComputerConfig, Config)
|
|
|
|
_Logger.Info("ComputerConfig exists and will be used. [{0}]", _ComputerConfigPath)
|
|
Catch ex As Exception
|
|
_Logger.Error(ex)
|
|
_Logger.Warn("Computer config could not be loaded!")
|
|
End Try
|
|
_WriteAllValuesToUserConfig = False
|
|
Else
|
|
_Logger.Debug("Computer config does not exist.")
|
|
_WriteAllValuesToUserConfig = True
|
|
End If
|
|
|
|
Return Config
|
|
End Function
|
|
|
|
Private Function LoadUserConfig(ByVal Config As T) As T
|
|
If File.Exists(_UserConfigPath) Then
|
|
Try
|
|
Dim oUserConfig = ReadFromFile(_UserConfigPath)
|
|
_Logger.Debug("UserConfig exists and will be used. [{0}]", _UserConfigPath)
|
|
|
|
' if user config exists
|
|
If Not IsNothing(oUserConfig) Then
|
|
' Copy values from user config to final config
|
|
If _WriteAllValuesToUserConfig Then
|
|
CopyValues(oUserConfig, Config, New List(Of Type))
|
|
Else
|
|
CopyValues(oUserConfig, Config, _ExcludedAttributes)
|
|
End If
|
|
End If
|
|
Catch ex As Exception
|
|
_Logger.Error(ex)
|
|
_Logger.Warn("User config could not be loaded!")
|
|
End Try
|
|
Else
|
|
_Logger.Debug("User config does not exist. Default config will be created")
|
|
WriteToFile(Config, _UserConfigPath, False)
|
|
End If
|
|
|
|
Return Config
|
|
End Function
|
|
|
|
Private Function TestHasAttribute(Config As T, AttributeType As Type) As Boolean
|
|
For Each oProperty As PropertyInfo In Config.GetType.GetProperties()
|
|
If Attribute.IsDefined(oProperty, GetType(ConnectionStringAttribute)) Then
|
|
Return True
|
|
End If
|
|
Next
|
|
|
|
Return False
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Serialize a config object to byte array
|
|
''' </summary>
|
|
''' <param name="Data"></param>
|
|
''' <returns></returns>
|
|
Private Function Serialize(Data As T) As Byte()
|
|
Try
|
|
_Logger.Debug("Serializing config object")
|
|
|
|
Using oStream = New MemoryStream()
|
|
_Serializer.Serialize(oStream, Data)
|
|
_Logger.Debug("Object serialized.")
|
|
Return oStream.ToArray()
|
|
End Using
|
|
Catch ex As Exception
|
|
_Logger.Error(ex)
|
|
Throw ex
|
|
End Try
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Write an object to disk as xml
|
|
''' </summary>
|
|
''' <param name="Data">The object to write</param>
|
|
''' <param name="Path">The file name to write to</param>
|
|
Private Sub WriteToFile(Data As T, Path As String, ForceAll As Boolean)
|
|
Try
|
|
_Logger.Debug("Saving config to: {0}", Path)
|
|
|
|
' If config was loaded from computer config,
|
|
' DO NOT save connection string, etc. to user config
|
|
If _WriteAllValuesToUserConfig = False And ForceAll = False Then
|
|
Data = FilterValues(Data, _ExcludedAttributes)
|
|
End If
|
|
|
|
Dim oBytes = Serialize(Data)
|
|
|
|
Using oFileStream = New FileStream(Path, FileMode.Create, FileAccess.Write)
|
|
oFileStream.Write(oBytes, 0, oBytes.Length)
|
|
oFileStream.Flush()
|
|
End Using
|
|
Catch ex As Exception
|
|
_Logger.Warn("Could not save config to {0}", Path)
|
|
_Logger.Error(ex)
|
|
Throw ex
|
|
End Try
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Reads an xml from disk and deserializes to object
|
|
''' </summary>
|
|
''' <returns></returns>
|
|
Private Function ReadFromFile(Path As String) As T
|
|
Try
|
|
_Logger.Debug("Loading config from: {0}", Path)
|
|
Dim oConfig As T
|
|
|
|
Using oReader As New StreamReader(Path)
|
|
oConfig = _Serializer.Deserialize(oReader)
|
|
End Using
|
|
|
|
' If oConfig is Nothing, a config file was created but nothing was written to it.
|
|
' In this case we need to create oConfig from defaults so we have at least some config object
|
|
If oConfig Is Nothing Then
|
|
_Logger.Debug("Config file is valid but empty. Loading default values")
|
|
oConfig = Activator.CreateInstance(_BlueprintType)
|
|
End If
|
|
|
|
Return oConfig
|
|
Catch ex As Exception
|
|
_Logger.Warn("Could not load config from {0}", Path)
|
|
_Logger.Error(ex)
|
|
Throw ex
|
|
End Try
|
|
End Function
|
|
End Class
|