diff --git a/Config/Config.vbproj b/Config/Config.vbproj index 4e569b1a..7d7203f6 100644 --- a/Config/Config.vbproj +++ b/Config/Config.vbproj @@ -73,7 +73,9 @@ + + True @@ -89,7 +91,6 @@ Settings.settings True - diff --git a/Config/ConfigAttributes.vb b/Config/ConfigAttributes.vb new file mode 100644 index 00000000..d5b64582 --- /dev/null +++ b/Config/ConfigAttributes.vb @@ -0,0 +1,5 @@ +Public Class ConfigAttributes + Public Class ConnectionStringAttribute + Inherits Attribute + End Class +End Class diff --git a/Config/ConfigManager.vb b/Config/ConfigManager.vb index 7faa0a6c..c1e9a300 100644 --- a/Config/ConfigManager.vb +++ b/Config/ConfigManager.vb @@ -1,6 +1,8 @@ Imports System.IO +Imports System.Reflection Imports System.Xml.Serialization Imports DigitalData.Modules.Logging +Imports DigitalData.Modules.Config.ConfigAttributes Public Class ConfigManager(Of T) Private Const USER_CONFIG_NAME As String = "UserConfig.xml" @@ -11,7 +13,8 @@ Public Class ConfigManager(Of T) Private ReadOnly _File As Filesystem.File Private ReadOnly _UserPath As String Private ReadOnly _ComputerPath As String - Private _CurrentDataPath As String + + Private _ForceUserConfig As Boolean ''' ''' The blueprint class from which the default config is created @@ -21,29 +24,22 @@ Public Class ConfigManager(Of T) Public ReadOnly Property Config As T - ''' ''' Creates a new instance of the ConfigManager ''' - ''' - ''' Public Class Config - ''' Public Property StringEntry As String = "TEST" - ''' Public Property BoolEntry As Boolean = True - ''' Public Property IntEntry As Integer = 123 - ''' End Class - ''' - ''' Dim oConfigManager = New ConfigManager(Of Config)(_LogConfig, Application.UserAppDataPath, Application.CommonAppDataPath) - ''' + ''' ''' LogConfig instance - ''' The first path to check for a config file, eg. AppData - ''' The second path to check for a config file, eg. ProgramData - Public Sub New(LogConfig As LogConfig, UserConfigPath As String, ComputerConfigPath As String) + ''' The path to check for a user config file, eg. AppData + ''' The path to check for a computer config file, eg. ProgramData + ''' Override values from ComputerConfig with UserConfig + Public Sub New(LogConfig As LogConfig, UserConfigPath As String, ComputerConfigPath As String, Optional ForceUserConfig As Boolean = False) _LogConfig = LogConfig _Logger = LogConfig.GetLogger() _File = New Filesystem.File(_LogConfig) _UserPath = Path.Combine(UserConfigPath, USER_CONFIG_NAME) _ComputerPath = Path.Combine(ComputerConfigPath, COMPUTER_CONFIG_NAME) + _ForceUserConfig = ForceUserConfig _Blueprint = Activator.CreateInstance(Of T) _Serializer = New XmlSerializer(_Blueprint.GetType) @@ -72,58 +68,130 @@ Public Class ConfigManager(Of T) End Sub ''' - ''' Creates a new instance of the ConfigManager. + ''' Creates a new ConfigManager with a single (user)config path ''' - ''' - ''' Public Class Config - ''' Public Property StringEntry As String = "TEST" - ''' Public Property BoolEntry As Boolean = True - ''' Public Property IntEntry As Integer = 123 - ''' End Class - ''' - ''' Dim oConfigManager = New ConfigManager(Of Config)(_LogConfig, Application.UserAppDataPath) - ''' - ''' LogConfig instance - ''' The path to check for a config file, eg. AppData + ''' + ''' Public Sub New(LogConfig As LogConfig, ConfigPath As String) - MyClass.New(LogConfig, ConfigPath, ConfigPath) + MyClass.New(LogConfig, ConfigPath, ConfigPath, ForceUserConfig:=True) End Sub ''' ''' Save the current config object to `UserConfigPath` ''' - Public Sub Save() - WriteToFile(_Config, _UserPath) + ''' True if save was successful, False otherwise + Public Function Save() As Boolean + Try + WriteToFile(_Config, _UserPath) + Return True + Catch ex As Exception + _Logger.Error(ex) + Return False + End Try + End Function + + Private Sub CopyValues(Of T)(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 + Dim oValue = oProperty.GetValue(Source, Nothing) + If Not IsNothing(oValue) Then + oProperty.SetValue(Target, oValue, Nothing) + End If + Next End Sub - ''' - ''' First check if a user config exists and if it does, load it. - ''' If not, check if a systemwide config exists and and if it does, load it. - ''' Otherwise, create a user config using the default values from the supplied config class `T` - ''' - ''' Private Function LoadConfig() As T - Dim oConfig As T + ' first create an empty/default config object + Dim oConfig = Activator.CreateInstance(_Blueprint.GetType) + ' then Try to load computer config + oConfig = LoadComputerConfig(oConfig) + ' now try to load userconfig + oConfig = LoadUserConfig(oConfig) + Return oConfig + End Function - If File.Exists(_UserPath) Then - _Logger.Debug("Loading config from UserPath: {0}", _UserPath) - _CurrentDataPath = _UserPath - oConfig = ReadFromFile(_UserPath) - ElseIf File.Exists(_ComputerPath) Then - _Logger.Debug("Loading config from ComputerPath: {0}", _ComputerPath) - _CurrentDataPath = _ComputerPath - oConfig = ReadFromFile(_ComputerPath) + Private Function LoadComputerConfig(ByVal Config As T) As T + If File.Exists(_ComputerPath) Then + Try + Dim oComputerConfig = ReadFromFile(_ComputerPath) + + ' if a computer config exists, copy values + ' from computer config to final config + If Not IsNothing(oComputerConfig) Then + CopyValues(oComputerConfig, Config) + End If + Catch ex As Exception + _Logger.Error(ex) + _Logger.Warn("Computer config could not be loaded!") + End Try Else - _Logger.Debug("Creating default config in UserPath: {0}", _UserPath) - _CurrentDataPath = _UserPath - oConfig = Activator.CreateInstance(_Blueprint.GetType) - - WriteToFile(_Config, _UserPath) + _ForceUserConfig = True End If + Return Config + End Function + + Private Function LoadUserConfig(ByVal Config As T) As T + If File.Exists(_UserPath) Then + Try + Dim oUserConfig = ReadFromFile(_UserPath) + + ' if user config exists + If Not IsNothing(oUserConfig) Then + Dim oExcludedAttributes As New List(Of Type) + If Not _ForceUserConfig Then + oExcludedAttributes.Add(GetType(ConnectionStringAttribute)) + End If + + ' Copy values from user config to final config + CopyValues(oUserConfig, Config, oExcludedAttributes) + End If + + 'Dim oConnectionProperty = TestHasAttribute(oConfig, GetType(ConnectionStringAttribute)) + Catch ex As Exception + _Logger.Error(ex) + _Logger.Warn("User config could not be loaded!") + End Try + End If + + Return Config + End Function + + Private Function LoadDefaultConfig() As T + _Logger.Debug("Creating default config in UserPath: {0}", _UserPath) + Dim oConfig = Activator.CreateInstance(_Blueprint.GetType) + + Try + WriteToFile(oConfig, _UserPath) + Catch ex As Exception + _Logger.Warn("Could not create default config in UserPath: {0}", _UserPath) + End Try + Return oConfig End Function + Private Function TestHasAttribute(Config As T, AttributeType As Type) As String + For Each oProperty As PropertyInfo In Config.GetType.GetProperties() + If Attribute.IsDefined(oProperty, GetType(ConnectionStringAttribute)) Then + Return oProperty.Name + End If + Next + + Return Nothing + End Function + ''' ''' Serialize a config object to byte array ''' diff --git a/Config/ConfigSample.vb b/Config/ConfigSample.vb new file mode 100644 index 00000000..f6ded688 --- /dev/null +++ b/Config/ConfigSample.vb @@ -0,0 +1,7 @@ +Imports DigitalData.Modules.Config.ConfigAttributes + +Public Class ConfigSample + + + Public Property ConnectionString As String +End Class diff --git a/Config/My Project/AssemblyInfo.vb b/Config/My Project/AssemblyInfo.vb index e988c66c..7a591066 100644 --- a/Config/My Project/AssemblyInfo.vb +++ b/Config/My Project/AssemblyInfo.vb @@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices ' übernehmen, indem Sie "*" eingeben: ' - + diff --git a/Config/SinceVersionAttribute.vb b/Config/SinceVersionAttribute.vb deleted file mode 100644 index f3b94c7e..00000000 --- a/Config/SinceVersionAttribute.vb +++ /dev/null @@ -1,9 +0,0 @@ -Public Class SinceVersionAttribute - Inherits Attribute - - Public Version As Version - - Public Sub New(Version As String) - Me.Version = New Version(Version) - End Sub -End Class \ No newline at end of file