如何在.NET Core中使用.settings文件?

Ale*_*ing 4 c# msbuild .net-core

我正在将应用程序移植到依赖于.settings文件的.NET Core 。不幸的是,我找不到从.NET核心读取它的方法。通常,.csproj将以下行添加到中将生成一个TestSettings类,该类可以让我读取设置。

<ItemGroup>
    <None Include="TestSettings.settings">
        <Generator>SettingsSingleFileGenerator</Generator>
    </None>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

不幸的是,这似乎不再有任何作用。我什至无法验证SettingsSingleFileGenerator运行情况。这个GitHub问题表明这是新.csproj格式的错误,但是没有人提供替代方法。

.settings在.NET Core 中读取文件的正确方法是什么?

McG*_*V10 5

对于.NET Core 2.x,请使用Microsoft.Extensions.Configuration名称空间(请参阅下面的注释),NuGet上有大量扩展,您需要抓取这些扩展来读取从环境变量到Azure Key Vault的各种源(但实际上是JSON文件) ,XML等)。

这是一个来自控制台程序的示例,该示例在Kestrel启动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();
Run Code Online (Sandbox Code Playgroud)

然后,在需要设置的代码中,您只需引用Configuration或注册IConfiguration依赖项注入或其他方法即可。

注意:IConfiguration是只读的,可能永远不会对此注释保持持久性。因此,如果需要阅读和写作,则需要其他选择。可能System.Configuration 没有设计师。

  • 这个答案只对了一半。如果您来这里寻找一个存储来读取和保存数据,请不要走 Microsoft.Extensions.Configuration 道路,它目前是不可变的(https://github.com/aspnet/Configuration/issues/385)。看来 System.Configuration.ConfigurationManager 或自定义 Json.Net impl 是可行的方法。啊。 (2认同)

Ale*_*ing 1

正如我在问题中所问的那样,这不可能是“正确的”,但我将其用作权宜之计,直到出现更合理的东西。我不能保证它对其他人也有效。

将您的.settings文件作为嵌入式资源包含在内,然后按如下方式使用它:

private static readonly ConfigurationShim Configuration = new ConfigurationShim("MyApp.Settings.settings");
public static bool MyBoolSetting => (bool) Configuration["MyBoolSetting"];
Run Code Online (Sandbox Code Playgroud)

代码:

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));
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

  • _请_有人找到替代方案。我犹豫着是否将其发布在这里;有人可能会使用它。 (2认同)