aloneguid / config Goto Github PK
View Code? Open in Web Editor NEW⚙ Config.Net - the easiest configuration framework for .NET developers. No BS.
License: MIT License
⚙ Config.Net - the easiest configuration framework for .NET developers. No BS.
License: MIT License
Add possibility to pass relative file path into file storages like INI or JSON. This may be useful in some situations.
To avoid direct newtonsoft.json dependencies
Think of a better way to create instances of settings containers. What I've seen so far is a plethora of singletons in code, seems repetitive enough.
The order of items added using AddStore
is not honoured because the underlying container is a ConcurrentBag
, which is unordered, so the enumerator does not return the values in the order they were added, and store priorities are ignored.
This is a major issue if you're using more than one store!
When an interface derives from another interface, all properties should be able to be used in configuration.
When specifying positional parameters in commandline and they have :
in the value, like program.exe c:\path.txt
parser considers :
as key-value separator and doesn't extract the value.
At the moment if no separator is found the parameter is ignored, however it's sometimes useful to still get it. Need to think how.
Currently to read actual value from the option I need to write it in the one of the following ways:
var settings = new AllSettings();
int value1 = settings.IntegerOption;
var value2 = (int)settings.IntegerOption;
I don't like to write type or use implicit cast because I need to know actual setting type when I writing the code. And it slows down code typing speed much.
It would be useful to have a method or property to get actual value from option. Something like this:
var settings = new AllSettings();
var value = settings.IntegerOption.Value;
or
var settings = new AllSettings();
var value = settings.IntegerOption.GetValue();
Currently there is one method accepting argument list which can accept null to use system command line parameters. Seems like null is almost always used, would make sense to have parameterless overload.
Hi Config.net
First of all, it's been a while since I've last used this package - NICE WORK on the doc and in the usage of Interfaces - very pleased with that.
I have an issue with datetime and miliseconds getting lost.
The "u" in DateTime.ToString skips miliseconds.
I've tried adding a TypeParser supporting DateTime - tried to overwrite the existing TypeParser in Core. My own parser is used in writing but not in "reading".
I remember earlier it was possible to overwrite a TypeParser.
Lets say I would like to use "O" instead of "u" - is this possible? I know it will fault in backward compatibility - is there possible to overwrite the current format?
Let me know if I should clearify things a bit.
Is there any particular reason readonly fields have been chosen? Is this simply some sort of preference for reflection identification of relevant properties?
This causes a major issue in that it's not easily possible to define interfaces for configuration objects, so if you define IServerConfiguration
you can only specify an interface by implicitly specifying interface members and pointing them to a backing read-only field:
public interface IServerConfiguration
{
Option<string> HostListenAddress { get; }
Option<string> ConnectionString { get; }
}
public class ServerConfiguration : SettingsContainer, IServerConfiguration
{
public readonly Option<string> HostListenAddress = new Option<string>();
public readonly Option<string> ConnectionString = new Option<string>();
Option<string> IServerConfiguration.HostListenAddress => this.HostListenAddress;
Option<string> IServerConfiguration.ConnectionString => this.ConnectionString;
protected override void OnConfigure(IConfigConfiguration configuration)
{
configuration.UseJsonFile("./config.json");
}
}
Is there anything stopping us from modifying the library to use properties?
To further separate configuration from the application bits (and their deployment), consider implementing a reader that would allow for the backing configuration data to be housed in a Git repository.
Complicating Factors:
The type is not used and implementation is flawed
Hello,
The readme mentions the ability to create custom type parsers by implementing ITypeParser.
Sadly I can't figure out a way to actually register the parser.
By looking at the code it doesn't seem like that is possible at all.
Password ends up combination of password and domain.
Fix: to replace string s with creds in Utils class. Code and test to follow.
Hello @aloneguid and team, as title I can not debug TryParse method in custom parser. I don't sure if it is problem of my computer. I can debug ToRawString
.
btw, how to verify settings when app start. I want to make sure that it will throw error if there is some mistakes, for example, if we setup setting wrong format then application should warning us before it does anything.
Here is my custom parser:
public class TimespanRangeParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(List<KeyValuePair<TimeSpan, TimeSpan>>) };
public string ToRawString(object value)
{
if (value == null) return null;
if (value is List<KeyValuePair<TimeSpan, TimeSpan>>)
{
var timeRange = value as List<KeyValuePair<TimeSpan, TimeSpan>>;
if (timeRange != null)
{
var result = string.Empty;
foreach (var item in timeRange)
{
result += ($"|{item.Key.Hours:00}:{item.Key.Minutes:00}:{item.Key.Seconds:00},{item.Value.Hours:00}:{item.Value.Minutes:00}:{item.Value.Seconds:00}");
}
if (result.Length > 0)
{
return result.Substring(1);
}
}
}
return null;
}
public bool TryParse(string value, Type t, out object result)
{
if (value == null)
{
result = null;
return false;
}
if (t == typeof(List<KeyValuePair<TimeSpan, TimeSpan>>))
{
var dtRange = new List<KeyValuePair<TimeSpan, TimeSpan>>();
var strRanges = new List<string>();
strRanges.AddRange(value.Split('|'));
foreach (var item in strRanges)
{
var arr = item.Split(',');
var start = TimeSpan.Parse(arr[0]);
var end = TimeSpan.Parse(arr[1]);
dtRange.Add(new KeyValuePair<TimeSpan, TimeSpan>(start, end));
}
result = dtRange;
return true;
}
result = null;
return false;
}
}
AppSetting
<add key="TimeToRun" value="20:30:01,23:59:02|02:15:03,04:59:04" />
ConfigBuilder
public static ICrawlerSettings Settings = new ConfigurationBuilder<ICrawlerSettings>()
.UseTypeParser(new TimespanRangeParser())
.UseAppConfig()
.Build();
When configuration option is a path to directory or file it's sometimes more useful to get the wrapped structure.
It would be great to have interfaces as getter properties in configuration interfaces themselves. It will allow some sort of reusability when configuration sections have an identical structure i.e.
interface ICredentials
{
string Username {get;}
string Password {get;}
}
interface IUserCreds
{
ICredentials NormalCreds { get; }
ICredentials AdminCreds { get; }
}
``
I don't have any config file in my project since I like the tool to look for an existing config file first. My assumption is that the line below will create a new config file and write the default settings in it but it doesn't work. Is there a build in method to do this?
Settings = new ConfigurationBuilder<ApplicationSettings>()
.UseAppConfig()
.Build();
Support entity arrays i.e. I'd like to save and load an array of interface instances.
When running the UnitTests on a Windows-PC with german locale settings, the DoubleParser-Tests fail.
On Parsing the String-Values, there is no locale set, so the system locale is used. Due to the fact that the test-data has a point as decimal separator (for german locale a comma would be correct), the parser results in a wrong number (e.g. "1,797693" results in double value "1797693").
Changing the test-data to a german locale format with comma, will result in correct parsing the value, but the test fails anyway, because the method TypeParser.ToRawString(...) uses an invariant culture, so "1,797693" <> "1.797693".
Always use a defined locale (invariant or en-EN, or whatever) and document that. Hard fail on other formats.
Let the parser determine the correct locale (e.g. scanning for points and commas) -> can be tricky for special locales -> "magic" can introduce hard to find bugs.
Passing an optional argument to the Parser-Contructor to set the locale to use for TryParse() and toRawString() -> would be always correct, but introduces complexity for the library-user.
Yaml links: http://yaml.org/
If I want to supply friendly cmdline apps I might want to allow the user to omit the key part of the keyvalue pair. As an example, rather than
parq InputFilePath=/path/to/file
I might want to let my users simply enter:
parq /path/to/file
using config.NET, I am forced to force my users to enter the full key value pair, rather than defaulting the key to populate by ordinal.
This would be rocking:
class AppSettings : SettingsContainer
{
**[DefaultOrdinal(0)]** //awesomeness here
public readonly Option<string> InputFilePath = new Option<string>();
If I try to get for example an int, and type Console.WriteLine(Settings.PortNumber.ToString()) it writes "PortNumber" to the console, rather than the actual port number.
If I create a new variable first (int port = Settings.PortNumber;) and then call port.ToString() I get what I expect - I assume that bypasses the ToString() override, so the problem ought to be in the override somewhere.
Is anyone aware of this and working on it, or should I dig deeper?
Weird thing, can't read a '0.0.0.0' value
e.g.
ControllerServerIP=0.0.0.0
Please fix.
There is some code duplication between Storage.Net (azure tables, blobs etc.) and this library, which is just stupid. I think it's better to have a writer which can accept ITableStorage or IBlobStorage. That will also automatically add any target that Storage.Net suppots now and in the future.
I think you need to use new ConfigurationBuilder(), rather than the interface. I suppose you have to decide whether it's correct to dynamically create each property, or have a configuration class. A class is more flexible, as the user can add functions such derived properties or license key decryption stuff.
In current implementation, if I use readonly property, values are writing and then reading properly but file storage file looks awkward. For example ini storage with the following code:
public class AllSettings : SettingsContainer
{
public Option<string> AuthClientId { get; } = new Option<string>("Id");
public Option<string> AuthClientSecret { get; } = new Option<string>("Secret");
protected override void OnConfigure(IConfigConfiguration configuration)
{
configuration.UseIniFile(@"path_to_config.ini");
}
}
Produces the following file:
<AuthClientId>k__BackingField=Id
<AuthClientSecret>k__BackingField=Secret
Similar thing happens for JSON storage:
{
"<AuthClientId>k__BackingField":"Id",
"<AuthClientSecret>k__BackingField":"Secret"
}
If I specify option name file is filling up correctly. It would be great to populate default name from option property correctly as well.
Current workaround for this issue is to create property like this:
public Option<string> AuthClientId { get; } = new Option<string>(nameof(AuthClientId), "TestId");
I want to store a lot of settings in the single file. In this case, SettingsContainer becomes a mess of huge amount of properties which is hard to maintain and use.
It would be nice to have an opportunity to create nested options. Something like this:
public class NestedConfig
{
public Option<string> UserId { get; } = new Option<string>(nameof(UserId), "UserId");
public Option<string> UserName { get; } = new Option<string>(nameof(UserName), "UserName");
}
public class AllSettings : SettingsContainer
{
public Option<string> AuthClientId { get; } = new Option<string>(nameof(AuthClientId), "TestId");
public Option<string> AuthClientSecret { get; } = new Option<string>("Secret");
public Option<int> Quantity { get; } = new Option<int>();
public NestedConfig Nested { get; } = new NestedConfig();
protected override void OnConfigure(IConfigConfiguration configuration)
{
configuration.UseJsonConfig(@"path_to_config.json");
}
}
Then it could be accessed in code like this:
var settings = new AllSettings();
string userId = settings.Nested.UserId;
settings.Nested.UserId.Write("test");
This will help to work with a lot of settings stored in single file and avoid naming conflicts.
.INI provider should have a settings "comments allowed" which when false can ignore the ';' character anywhere in the string.
I have implemented a custom parser, but I do not see how to register it. I do not see a ContainerConfiguration in version 4.5.0.76. Was it removed? Was it added to a later version?
Hi Config.net
I am writing because I have detected an issue with the default datetimeparser.
When writing datetime to file, the .ToString("u") is used. The value is stored correct.
Upon reading the stored datetime value as string, the time is not correct. Time is not correct due to timezone (z) in the stored string.
Solution could be:
A) .ToUniversalTime.ToString("u")
B) Allow supported datatypes to be replaced. Lets say I have a custom DateTimeParser I want to replace the current implementation, "RemoveParser" could come in handy.
Sample:
"Original value": 2017-07-13 22:28:52
Stored value: 2017-07-13 22:28:52Z
Read value: 2017-07-14 00:28:52
Let me know if you need further information.
I'm currently using Rider to develop Mono-target net462
applications, and when attempting to inspect an interface instance, the debugger crashes. I'm unsure what the cause is, and I haven't been able to narrow down a cause in the interface itself. Even a simple string-typed single-property interfaces causes this behaviour.
I'm using the INI file store. I've attached the crash log from Mono.
This is under Mono 5.4.1.7, and Linux Mint 18.3. I'm using Rider, and I have the .NET Core SDK installed.
It is not possible to set string values within an string array parameter that have whitespaces (e.g. filenames /paths). Surrounding with hyphens does not help, because the StringArrayParser justs splits by whitespace.
Example:
TestArrayWSpace="testArrayA and B","testArrayC","TestArrayD or E"
will result in
testArrayA|and|B|testArrayC|TestArrayD|or|E
instead of
testArrayA and B|testArrayC|TestArrayD or E
Solution:
Due to the fact, that the commandline parser removes the hypens, additional single hyphens could be used to mark these strings. The StringArrayParser additionally needs to respect those (maybe first run a regex to extract the single-hyphend strings) (StringArrayParser.cs:21).
Example:
TestArrayWSpace="'testArrayA and B'","testArrayC","'TestArrayD or E'"
public interface ICallableConfig
{
string GetFirst(string sectionName, string key);
[Option(Alias = "A")]
string GetSecond(string sectionName);
[Option(DefaultValue = "n/a")]
string GetThird(string name);
void SetFirst(string name);
INestedCallableConfig Nested { get; }
}
public interface INestedCallableConfig
{
string GetNested(string sectionName);
}
calling _config.Nested.GetNested("section");
does not return a proper value.
your ITypeParser is the type of thing I meant, where MyTypes.AddressSerialiser might refer to a static class that implements that interface if you're overriding the default etc. As I said, probably unnecessary for now :)
I can add another property to Option a tribute, like WithTypeParser.
string array can be supported natively.
is there any nuget package?
Hello,
Having an app.config like this one:
<configuration>
<configSections>
<section name="CategorizerSettings" type="???" />
</configSections>
<CategorizerSettings>
<category Text="Google" Folder="GoogleFolder" />
<category Text="Yahoo" Folder="YahooFolder" />
</CategorizerSettings>
<appSettings>
<add key="SourceFolder" value="MySourceFolder" />
</appSettings>
...
I can read easly app key
SourceFolder, but how I can read the categories into CategorizerSettings
section?
Thanks
The current support for 'saving' configuration is rather poor as it is only possible to set individual configuration values through property setters, which doesn't work nicely with configuration stores that maintain their own state and require explicit change commits:
Would it make sense to either...
IPersistableConfiguration
) which provides a method SaveChanges
, which then persists the configuration of each store through the proxyOr is this a feature which is generally not desired?
At the moment it's just a weak binding in a form of param name to param value, however it would be an excellent feature to support command line fully.
That includes generating help pages, supporting positional arguments, validating parameter sets etc.
I love many aspects of the project. I haven't been looking more than twenty minutes, but I like the combination of not accessing via strings but properties and the fallback system with several sources - I'm not sure any other configuration system has that out of the box. Nini uses strings, YamlDotNet is more or less undocumented, and System.Configuration is just a shell to implement everything yourself on.
So, I am considering going with Config.Net, but before I delve deeper, there's an issue to resolve. I failed to find the license terms, which makes it legally difficult. Is it a regular MIT license, or did you have something else in mind?
As a side-note, I'm submitting this as an issue, because I couldn't find any discussion forum or contact method, besides a Disqus comment field on your blog, which didn't feel quite like an official channel.
the class has a dependency, but if the interface is moved to another project that's dependency is removed. As a result your main configuration project needs a reference, but no other projects in your solution do (I think). We'll have to check it and see.
Sometimes you don't have file on disk, especially when there is not disk available, however you do have a file content available. Apparently writing will not be possible, however it should be allowed to initialise a store from the file content.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.