Imports System.IO Imports System.Xml.Serialization Imports DigitalData.Modules.Logging Public Class ConfigManager(Of T) Private Const USER_CONFIG_NAME As String = "UserConfig.xml" Private Const COMPUTER_CONFIG_NAME As String = "ComputerConfig.xml" Private ReadOnly _LogConfig As LogConfig Private ReadOnly _Logger As Logger Private ReadOnly _File As Filesystem.File Private ReadOnly _UserPath As String Private ReadOnly _ComputerPath As String Private _CurrentDataPath As String ''' ''' The blueprint class from which the default config is created ''' Private ReadOnly _Blueprint As T Private ReadOnly _Serializer As XmlSerializer 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) _LogConfig = LogConfig _Logger = LogConfig.GetLogger() _File = New Filesystem.File(_LogConfig) _UserPath = Path.Combine(UserConfigPath, USER_CONFIG_NAME) _ComputerPath = Path.Combine(ComputerConfigPath, COMPUTER_CONFIG_NAME) _Blueprint = Activator.CreateInstance(Of T) _Serializer = New XmlSerializer(_Blueprint.GetType) If Not Directory.Exists(UserConfigPath) Then _Logger.Debug("UserConfigPath {0} did not exist and was created", UserConfigPath) Directory.CreateDirectory(UserConfigPath) End If If Not _File.TestPathIsDirectory(UserConfigPath) Then _Logger.Warn("UserConfigPath {0} is not a directory", UserConfigPath) Throw New ArgumentException($"Path {UserConfigPath} is not a directory!") End If If Not Directory.Exists(ComputerConfigPath) Then _Logger.Debug("ComputerConfigPath {0} did not exist and was created", ComputerConfigPath) Directory.CreateDirectory(ComputerConfigPath) End If If Not _File.TestPathIsDirectory(ComputerConfigPath) Then _Logger.Warn("ComputerConfigPath {0} is not a directory", ComputerConfigPath) Throw New ArgumentException($"Path {ComputerConfigPath} is not a directory!") End If _Config = LoadConfig() End Sub ''' ''' Save the current config object to `UserConfigPath` ''' Public Sub Save() WriteToFile(_Config, _UserPath) 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 If IO.File.Exists(_UserPath) Then _Logger.Debug("Loading config from UserPath: {0}", _UserPath) _CurrentDataPath = _UserPath oConfig = ReadFromFile(_UserPath) ElseIf IO.File.Exists(_ComputerPath) Then _Logger.Debug("Loading config from ComputerPath: {0}", _ComputerPath) _CurrentDataPath = _ComputerPath oConfig = ReadFromFile(_ComputerPath) Else _Logger.Debug("Creating default config in UserPath: {0}", _UserPath) _CurrentDataPath = _UserPath oConfig = Activator.CreateInstance(_Blueprint.GetType) WriteToFile(_Config, _UserPath) End If Return oConfig End Function ''' ''' Serialize a config object to byte array ''' ''' ''' Private Function Serialize(Data As T) As Byte() Try _Logger.Debug("Serializing config object") Using oStream = New MemoryStream() _Serializer.Serialize(oStream, Data) Return oStream.ToArray() End Using Catch ex As Exception _Logger.Error(ex) Throw ex End Try End Function ''' ''' Write an object to disk as xml ''' ''' The object to write ''' The file name to write to Private Sub WriteToFile(Data As T, Path As String) Try _Logger.Debug("Saving config to: {0}", Path) 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.Error(ex) Throw ex End Try End Sub ''' ''' Reads an xml from disk and deserializes to object ''' ''' 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(_Blueprint.GetType) End If Return oConfig Catch ex As Exception _Logger.Error(ex) Throw ex End Try End Function End Class