我正在将一个应用程序移植到依赖于.settings
文件的.NET Core。不幸的是,我找不到从.NET Core阅读它的方法。通常,将以下行添加到.csproj
将生成TestSettings
类,该类可以让我阅读设置。
<ItemGroup>
<None Include="TestSettings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
</None>
</ItemGroup>
不幸的是,这似乎不再做任何事情。我什至无法验证SettingsSingleFileGenerator
根本运行。这个GitHub问题表明,这是新的.csproj
格式的错误,但没有人提供替代方案。
.net Core中读取.settings
文件的正确方法是什么?
for .net core 2.x,使用Microsoft.Extensions.Configuration
名称空间(请参见下面的注释(,并且在Nuget上有大量扩展名变量到Azure密钥库(但更真实地,JSON文件,XML等(。
这是控制台程序中的一个示例,该示例以我们的Azure站点启动时,以相同的方式检索设置:
: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();
然后在需要设置的代码中,您只需引用Configuration
即可注册IConfiguration
以进行依赖注入或其他。
注意:IConfiguration
是只读的,并且根据此评论可能永远不会持久。因此,如果需要阅读和写作,您将需要其他选择。可能System.Configuration
sans 设计师。
正如我在问题中所问的那样,这绝对不可能是"正确",但是我将其用作定格隙,直到出现更合理的事情为止。我不能保证它对其他任何人都有效。
将您的.settings
文件作为嵌入式资源,然后以此方式使用:
private static readonly ConfigurationShim Configuration = new ConfigurationShim("MyApp.Settings.settings");
public static bool MyBoolSetting => (bool) Configuration["MyBoolSetting"];
代码:
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));
});
}
}
移植现有项目时,我通常将生成的settings.designer.cs从旧项目复制到新项目。但是我知道,这对于更改设置文件或添加新的设置键是有害的。我还注意到,在安装新版本后,用户的设置被删除了,.net-framework-settings并非如此。