首页 文章

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

提问于
浏览
2

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

<ItemGroup>
    <None Include="TestSettings.settings">
        <Generator>SettingsSingleFileGenerator</Generator>
    </None>
</ItemGroup>

不幸的是,这似乎不再做任何事情 . 我甚至无法验证 SettingsSingleFileGenerator 是否完全运行 . 这GitHub issue表明这是新的 .csproj 格式的错误,但没有人提供替代方案 .

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

3 回答

  • 2

    对于.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();
    

    然后在您需要设置的代码中,您只需引用 Configuration 或注册 IConfiguration 以进行依赖注入或其他任何操作 .

  • 0

    正如我在问题中所提出的那样,这绝不是“正确的”,但我将这用作止损,直到出现更合理的东西 . 我无法保证它能为其他人工作 .

    将您的 .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));
            });
        }
    }
    
  • 0

    移植现有项目时,我通常会将生成的Settings.Designer.cs从旧项目复制到新项目 . 但我知道,这对于更改设置文件或添加新的设置键是不好的 . 我还注意到安装新版本后删除了用户的设置,但.net-Framework-Settings的情况并非如此 .

相关问题