Effective .NET library designed for working with and managing configs; has many useful features. This module provides a flexible framework that is pretty easy to use and straightforward. On the other hand, it has many functional attributes for making a tremendous and powerful config like BindabaleMember, Comment, Encryption, Required, Ordering, CustomName, Ignoring, CustomParser, etc.
$ dotnet add package G9ConfigManagementusing System;
using G9ConfigManagement.Abstract;
using G9ConfigManagement.Attributes;
using G9ConfigManagement.DataType;
public class SampleConfig : G9AConfigStructure<SampleConfig>
{
// Custom attribute for setting the order of a member in the config file.
[G9AttrOrder(4)]
// Custom attribute for setting the desired comment for config member.
[G9AttrComment("My custom comment.")]
public string ApplicationName { set; get; } = "My Custom Application";
// Custom attribute for ignoring a member.
[G9AttrIgnore]
public string User = "MyUser";
[G9AttrOrder(1)]
// Custom attribute for setting a member as a required member.
[G9AttrRequired]
// Custom attribute for encrypting a member.
[G9AttrEncryption("G9-KaPSgV9Yp6s3v", "H@McQfTjWnZr4u7x")]
public string ConnectionString =
"Server=myServerName\\myInstanceName;Database=myDataBase;User Id=myUsername;Password=myPassword;";
[G9AttrOrder(2)]
// Custom attribute for setting a custom name for a member.
[G9AttrCustomName("MyCustomBindableMember")]
// This data type creates a bindable member with the desired value type.
// The specified generic type is the desired value type for the bindable member,
// and the constructor parameter sets the default value of that (which is optional).
public G9DtBindableMember<string> CustomBindableMember
= new G9DtBindableMember<string>("My bindable value");
[G9AttrOrder(3)]
// Custom attribute for specifying the method of storing value for an Enum member.
// By default, an Enum member saves as a number.
[G9AttrStoreEnumAsString]
public ConsoleColor Color = ConsoleColor.DarkMagenta;
// The abstract class 'G9AConfigStructure' forces you to implement this.
// This structure specified the version of config that can't be null or without initialization.
public override G9DtConfigVersion ConfigVersion { set; get; } = new(1, 0, 0, 0);
}
var config = SampleConfig.GetConfig();
Console.WriteLine(config.ApplicationName); // My Custom Application
Console.WriteLine(config.CustomBindableMember); // Bindable Member
Console.WriteLine(config.Color); // DarkMagenta
// ...
{
"ConnectionString": "cXgv/MI9Il0RQK50yO93tEngSsM6pkgXR1aQ6QubS2Myf0qB6BdRSCnynbJgj4XrK3Yj2YGtih8EPiLeE067fbn2IGiikd7ylqCjAhLPGXAZdv1rw/9Nb5UOM2o0bYfW",
"MyCustomBindableMember": "My bindable value",
"Color": "DarkMagenta",
/* My custom comment. */
"ApplicationName": "My Custom Application",
"ConfigVersion": "1.0.0.0"
}
var config = SampleConfig.GetConfig();
config.CustomBindableMember.OnChangeValue +=
// The first parameter specifies the new value, and the second one specifies the old value.
(newValue, oldValue) =>
{
// Do anything
Console.WriteLine($"Old Value: {oldValue} | New Value: {newValue}");
};
// The value of a bindable member is accessible as below:
Console.WriteLine(config.CustomBindableMember.CurrentValue); // My bindable value
// Also, after initialization, you can change it manually as below:
// Note: using this method would lead to calling all assigned events.
config.CustomBindableMember.SetNewValue("New Value");
// Setting custom instance for initialization
SampleConfig.SetInstanceForInitialization(new SampleConfig
{
ApplicationName = "My App",
Color = ConsoleColor.Green
});
// Using
var config = SampleConfig.GetConfig();
// Setting custom settings for config
SampleConfig.SetConfigSettings(new G9DtConfigSettings(
// A vital setting that specifies how the core must react when a change
// in the version occurs between the config structure and config file.
changeVersionReaction: G9EChangeVersionReaction.MergeThenOverwrite,
// Specifies the config file name
// By default, it used its structure name if not set.
configFileName: "MyConfig",
// Specifies the extension of the config file.
// By default, it is "json".
configFileExtension: "ini",
// Specifies the location of the config file.
// By default, it is "AppContext.BaseDirectory" that specifies the application directory.
configFileLocation: AppContext.BaseDirectory,
// Specifies that if the specified location of the config file
// does not exist, the core must create it or not.
// By default it is true.
enableAutomatedCreatingPath: true
));
// Using
var config = SampleConfig.GetConfig();
// Method to remake and restore the config by default initialized value.
// In this case, the config file is remade, and the config data is restored to the first structure.
SampleConfig.RemakeAndRestoreByDefaultValue();
// Method to remake and restore the config by custom initialized value.
// In this case, the created config file is remade, and the config data restore by the new specified value.
SampleConfig.RemakeAndRestoreByCustomValue(new SampleConfig());
// Method to restore a config structure to the default value that would be gotten from the config file.
SampleConfig.RestoreByConfigFile();
public class Sample
{
[G9AttrRequired]
public int Essential = 3;
}
public class Sample
{
[G9AttrOrder(3)]
public int C = 3;
[G9AttrOrder(2)]
public int B = 2;
[G9AttrOrder(1)]
public int A = 1;
}
// Expected result:
// {
// "A": 1,
// "B": 2,
// "C": 3,
// }
// A class that consists of custom parser methods.
public class CustomParser
{
// Custom parser for parsing the object to string.
// Note: The specified method must have two parameters (the first parameter is 'string' and the second one is 'G9IMemberGetter');
// in continuation, it must return an object value that is parsed from the string value.
public string ObjectToString(object objectForParsing, G9IMemberGetter accessToObjectMember)
{
if (accessToObjectMember.MemberType == typeof(CustomChildObject))
return ((CustomChildObject)objectForParsing).Number1 + "-" +
((CustomChildObject)objectForParsing).Number2 +
"-" + ((CustomChildObject)objectForParsing).Number3;
return default;
}
// Custom parser for parsing the string to object.
// Note: The specified method must have two parameters (the first parameter is 'object' and the second one is 'G9IMemberGetter');
// in continuation, it must return a string value that is parsed from the object value.
public object StringToObject(string stringForParsing, G9IMemberGetter accessToObjectMember)
{
if (accessToObjectMember.MemberType != typeof(CustomChildObject))
return default;
var numberData = stringForParsing.Split('-').Select(int.Parse).ToArray();
return new CustomChildObject
{
Number1 = numberData[0],
Number2 = numberData[1],
Number3 = numberData[2]
};
}
}
// Custom object
public class CustomObject
{
// This attribute has several overloads.
// The popular way (used below), for use, must specify the type of custom parse class in the first parameter,
// the second parameter specifies the string to object method name, and the last one specifies the object to string method name.
[G9AttrCustomParser(typeof(CustomParser), nameof(CustomParser.StringToObject),
nameof(CustomParser.ObjectToString))]
public CustomChildObject CustomChild = new();
}
// Custom child object
public class CustomChildObject
{
public int Number1 = 9;
public int Number2 = 8;
public int Number3 = 7;
}
// A class that consists of members with the attribute 'G9AttrEncryption'.
// This attribute has several overloads.
public class G9DtSampleClassForEncryptionDecryption
{
// With standard keys and default config
[G9AttrEncryption("G-JaNdRgUkXp2s5v", "3t6w9z$C&F)J@NcR")]
public string User = "G9TM";
// With custom nonstandard keys and custom config
[G9AttrEncryption("MyCustomKey", "MyCustomIV", PaddingMode.ANSIX923, CipherMode.CFB, enableAutoFixKeySize: true)]
public string Password = "1990";
// With custom nonstandard keys and custom config
[G9AttrEncryption("MyCustomKey", "MyCustomIV", PaddingMode.ISO10126, CipherMode.ECB, enableAutoFixKeySize: true)]
public DateTime Expire = DateTime.Now;
}
// Result
//{
// "User": "fESJe1TvMr00Q7BKTwVadg==",
// "Password": "sWNkdxQ=",
// "Expire": "C/WjS9oA+FRLw3myST4EowLiM22tTidXoG7hgJy3ZHo="
//}
Important note: The difference between the below structure and the attribute "G9AttrCustomParser" is that the mentioned attribute must be used on the desired member in a structure. But, by using this structure, if the parser finds the specified type in this structure, it automatically uses it (like the dependency injection process).
The abstract class 'G9ACustomTypeParser<>' enables you to define a custom parser for a specified type (Any type like a built-in .NET type or custom definition type).
This abstract class is a generic one where the generic parameter type specifies the type for parsing.
In addition, this abstract class has two abstract methods for parsing the string to object and wise versa that must implement by the programmer.
Furthermore, each class inherits by this abstract class is automatically used by JSON core (like a dependency injection process).
// Sample Class
public class ClassA
{
public string A = "G9";
public int B = 9;
}
// Custom parser structure for ClassA
// The target type must be specified in generic parameter 'G9ACustomTypeParser<ClassA>'
public class CustomParserStructureForClassA : G9ACustomTypeParser<ClassA>
{
// Method to parse specified object (ClassA) to string.
public override string ObjectToString(ClassA objectForParsing, G9IMemberGetter accessToObjectMember, Action<string> addCustomComment)
{
addCustomComment("My custom comment 1");
addCustomComment("My custom comment 2");
addCustomComment("My custom comment 3");
return objectForParsing.A + "TM-" + (objectForParsing.B - 3);
}
// Method to parse string to specified object (ClassA).
public override ClassA StringToObject(string stringForParsing, G9IMemberGetter accessToObjectMember)
{
var data = stringForParsing.Split("-");
return new ClassA()
{
A = data[0],
B = int.Parse(data[1])
};
}
}
Important note: The difference between the below structure and the attribute "G9AttrCustomParser" is that the mentioned attribute must be used on the desired member in a structure. But, by using this structure, if the parser finds the specified type in this structure, it automatically uses it (like the dependency injection process).
The abstract class 'G9ACustomGenericTypeParser' enables you to define a custom parser for a specified generic type.
Many parts of this structure are like the previous structure, with this difference that the target type for reacting (that is generic type) specified by inherited abstract class constructor.
In addition, in this case, the parser methods receive and return generic objects as the object type (not generic type) that, like the below example or in your own way (with the reflections), you can handle them.
// Sample Class
public class ClassB<TType>
{
public string A = "G9";
public TType B;
}
// Custom parser structure for generic ClassB<>
public class CustomParserStructureForClassB : G9ACustomGenericTypeParser
{
public CustomParserStructureForClassB()
// The target type in this case must be specified in inherited constructor like this
: base(typeof(ClassB<>))
{
}
// Method to parse specified generic object (ClassB<>) to string.
// The second parameter 'genericTypes', Specifies the type of generic parameters for target type.
public override string ObjectToString(object objectForParsing, Type[] genericTypes, G9IMemberGetter accessToObjectMember, Action<string> addCustomComment)
{
addCustomComment("My custom comment 1");
addCustomComment("My custom comment 2");
addCustomComment("My custom comment 3");
var fields = G9Assembly.ObjectAndReflectionTools
.GetFieldsOfObject(objectForParsing).ToDictionary(s => s.Name);
return fields[nameof(G9CClassD<object>.A)].GetValue<string>() + "-" +
fields[nameof(G9CClassD<object>.B)].GetValue();
}
// Method to parse string to specified generic object (ClassB<>).
// The second parameter 'genericTypes', Specifies the type of generic parameters for target type.
public override object StringToObject(string stringForParsing, Type[] genericTypes, G9IMemberGetter accessToObjectMember)
{
var data = stringForParsing.Split("-");
return new ClassB<string>()
{
A = data[0],
B = data[1]
};
}
}