How to use .settings files in .NET core?
Solution 1
For .NET Core 2.x, use the Microsoft.Extensions.Configuration
namespace (see note below), and there are tons of extensions on NuGet you'll want to grab for reading from sources ranging from environment variables to Azure Key Vault (but more realistically, JSON files, XML, etc).
Here's an example from a console program that retrieves settings the same way we use them when Kestrel starts up for our Azure sites:
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// This allows us to set a system environment variable to Development
// when running a compiled Release build on a local workstation, so we don't
// have to alter our real production appsettings file for compiled-local-test.
//.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
//.AddAzureKeyVault()
.Build();
Then in your code that needs settings, you just reference Configuration
or you register IConfiguration
for dependency injection or whatever.
Note: IConfiguration
is read-only and will likely never get persistence per this comment. So if reading AND writing are required, you'll need a different option. Probably System.Configuration
sans designer.
Solution 2
When porting existing projects I usually copy the generated Settings.Designer.cs from the old to the new project. But I know, this is bad for changing the Settings-file or adding new Settings-Keys. I also noticed that the user's settings were deleted after installing a new version, what was not the case with .net-Framework-Settings.
Solution 3
There's no way this is "proper", as I asked in the question, but I'm using this as a stop-gap until something more reasonable comes along. I cannot guarantee it will work for anyone else.
Include your .settings
file as an embedded resource, then use it like this:
private static readonly ConfigurationShim Configuration = new ConfigurationShim("MyApp.Settings.settings");
public static bool MyBoolSetting => (bool) Configuration["MyBoolSetting"];
Code:
internal class ConfigurationShim
{
private static readonly XNamespace ns = "http://schemas.microsoft.com/VisualStudio/2004/01/settings";
private readonly Lazy<IDictionary<string, object>> configuration;
public ConfigurationShim(string settingsResourceName)
{
configuration = new Lazy<IDictionary<string, object>>(
() =>
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(settingsResourceName))
using (var reader = new StreamReader(stream))
{
XDocument document = XDocument.Load(reader);
return document.Element(ns + "SettingsFile")
.Element(ns + "Settings")
.Elements(ns + "Setting")
.Select(ParseSetting)
.ToDictionary(kv => kv.Item1, kv => kv.Item2);
}
});
}
public object this[string property] => configuration.Value[property];
private static (string, object) ParseSetting(XElement setting)
{
string name = setting.Attribute("Name").Value;
string typeName = setting.Attribute("Type").Value;
string value = setting.Element(ns + "Value").Value;
Type type = Type.GetType(typeName);
IEnumerable<ConstructorInfo> ctors = GetSuitableConstructors(type);
IEnumerable<MethodInfo> staticMethods = GetSuitableStaticMethods(type);
object obj = null;
foreach (MethodBase method in ctors.Cast<MethodBase>().Concat(staticMethods))
{
try
{
obj = method.Invoke(null, new object[] {value});
break;
}
catch (TargetInvocationException)
{
// ignore and try next alternative
}
}
return (name, obj);
}
private static IEnumerable<MethodInfo> GetSuitableStaticMethods(Type type)
{
// To use a static method to construct a type, it must provide a method that
// returns a subtype of itself and that method must take a single string as
// an argument. It cannot be generic.
return type.GetMethods().Where(method =>
{
ParameterInfo[] parameters = method.GetParameters();
return !method.ContainsGenericParameters &&
method.IsStatic &&
parameters.Length == 1 &&
parameters[0].ParameterType.IsAssignableFrom(typeof(string)) &&
type.IsAssignableFrom(method.ReturnType);
});
}
private static IEnumerable<ConstructorInfo> GetSuitableConstructors(Type type)
{
// We need a constructor of a single string parameter with no generics.
return type.GetConstructors().Where(ctor =>
{
ParameterInfo[] parameters = ctor.GetParameters();
return !ctor.ContainsGenericParameters &&
parameters.Length == 1 &&
parameters[0].ParameterType.IsAssignableFrom(typeof(string));
});
}
}
Alex Reinking
I'm a PhD candidate at UC Berkeley studying programming language design. I work on Halide with my adviser, Jonathan Ragan-Kelley. I also work on Koka, specifically the Perceus reference counting system. In the past, I wrote the compiler for the P programming language at Microsoft. I play guitar and like to cook.
Updated on July 25, 2022Comments
-
Alex Reinking almost 2 years
I'm porting an application to .NET core which relies on a
.settings
file. Unfortunately, I can't find a way to read it from .NET core. Normally, adding the following lines to the.csproj
would generate aTestSettings
class that would let me read the settings.<ItemGroup> <None Include="TestSettings.settings"> <Generator>SettingsSingleFileGenerator</Generator> </None> </ItemGroup>
Unfortunately, this no longer seems to do anything. I can't even verify that the
SettingsSingleFileGenerator
runs at all. This GitHub issue suggests that this is a bug with the new.csproj
format, but no one has offered an alternative.What is the proper way of reading
.settings
files in .NET core? -
Alex Reinking about 6 yearsPlease, someone, find an alternative to this. I hesitated to post it here; someone might use it.
-
Achim Stuy about 6 yearsSee that net Core-Apps can have several configuration Providers: https://msdn.microsoft.com/en-us/magazine/mt632279.aspx
-
Alex Reinking about 6 yearsWhat's the difference between
Microsoft.Extensions.Configuration
andSystem.Configuration.ConfigurationManager
in .NET Core 2.0? -
McGuireV10 about 6 yearsIt's a complete rewrite / redesign. The
System
version was a monolithc, static, XML-focused feature. The new one is extensible and DI-friendly (which also makes it easier to unit test, if you're into that). -
McGuireV10 about 6 yearsI should also note that if you're using ASP.NET Core (not just .NET Core, or a .NET Standard class library), there is a different concept you should read about. Oh and the new system supports configuration-binding, which is deserializing a config section to a class with matching properties, very handy.
-
Louis Somers over 5 yearsThere would not be much reason to embed a settings file in your resources unless you only use it to write a default file when no settings file was found. The idea behind having a settings file in the first place is to enable users to configure stuff by editing it, which is not easy when it's embedded.
-
Felice Pollano over 5 yearsI actually think than using Directory.GetCurrentDirectory() being a potential cause of bugs ( typically is a newbie error )
-
Ani over 4 yearsThis answer is only half-correct. If you came here looking for a store to read from and persist data to, Don't go down the Microsoft.Extensions.Configuration road, it's currently immutable (github.com/aspnet/Configuration/issues/385). It seems like System.Configuration.ConfigurationManager or a custom Json.Net impl is the way to go. Ugh.
-
McGuireV10 over 4 years@Ani This isn't "half-correct" in any sense. Persistent data storage and configuration are two entirely separate concepts. If you landed here looking for persistent storage, you're on completely the wrong track. And it isn't "currently" immutable, if you actually read the backlogged item (also closed) it won't ever support persistence: comment
-
Ani over 4 yearsQ: I'm porting an application to .NET core which relies on a .settings file. A: For .NET Core 2.x, use the Microsoft.Extensions.Configuration namespace To me, that answer works only for READING values out of said file. Any nuances you may assume that "configuration" vs Settings is doesn't change that your answer seems to conflate the two by not explaining the differences. Also, the first line of your answer (quoted above) is clear in trying to steer OP to use
Microsoft.Extensions.Configuration
when it clearly wouldn't work like a Settings File does at all. -
Ani over 4 yearsThat the Microsoft.Extensions.Configuration team decided to KEEP this readonly does not make this answer more relevant, only less.
-
McGuireV10 over 4 years@Ani The OP never mentions writing to the file. You're literally making up a use-case that is completely unrelated to the question.
-
Ani over 4 yearsI think the note makes your answer crystal clear as opposed to the fact that it simply left out persistence entirely in its original form. Feel free to reject edits or rephrase your answer. Take it how you wish.