如何从ASP.Net Core配置文件合并多个阵列? [英] How to merge multiple arrays from ASP.Net Core configuration files?

查看:277
本文介绍了如何从ASP.Net Core配置文件合并多个阵列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的应用程序中动态加载和注册服务.为此,我需要能够从解决方案中的不同项目中加载配置文件,并将它们中的值合并到单个json数组中. 不幸的是,默认情况下,ASP.Net Core中的配置会覆盖值.

I would like dynamically load and register services in my application. To do that I need to be able to load configuration files from different projects in solution and merge values from them into single json array. Unfortunately by default in ASP.Net Core configuration overrides values.

我用以下代码注册文件(Program.cs文件的一部分):

I register files with following code (part of Program.cs file):

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((webHostBuilderContext, configurationbuilder) =>
            {
                var env = webHostBuilderContext.HostingEnvironment;
                configurationbuilder.SetBasePath(env.ContentRootPath);
                configurationbuilder.AddJsonFile("appsettings.json", false, true);

                var path = Path.Combine(env.ContentRootPath, "App_Config\\Include");

                foreach(var file in Directory.EnumerateFiles(path, "*.json",SearchOption.AllDirectories))
                {
                    configurationbuilder.AddJsonFile(file, false, true);
                }
                configurationbuilder.AddEnvironmentVariables();
            })
            .UseStartup<Startup>();

代码在App_Config\Include目录中搜索所有扩展名为*.json的文件,并将所有文件添加到配置构建器中.

The code searches for all files with *.json extension inside App_Config\Include directory and adds all of them to the configuration builder.

文件结构如下:

{
  "ServicesConfiguration": {
    "Services": [
      {
        "AssemblyName": "ParsingEngine.ServicesConfigurator, ParsingEngine"
      }
    ]
  }
}

如您所见,我得到了主要部分ServicesConfiguration,然后是Services数组,其中包含具有一个属性AssemblyName的对象.

As you can see I have got main section ServicesConfiguration then Services array with objects which have one attribute AssemblyName.

要读取这些值,请使用带有列表的ServicesConfiguration类:

To read those values I use ServicesConfiguration class with list:

public class ServicesConfiguration
    {
        public List<ServiceAssembly> Services { get; set; }
    }

该列表使用ServiceAssembly类:

public class ServiceAssembly
    {
        public string AssemblyName { get; set; }
    }

要加载该配置,我在构造函数级别(DI)使用IOptions:

To load that configuration I use IOptions at constructor level (DI):

Microsoft.Extensions.Options.IOptions<ServicesConfiguration> servicesConfiguration,

配置似乎已加载-但是文件中的值不会合并,但会被最后找到的文件覆盖.

And configuration seems to be loaded - but values from files are not merged but overridden by last found file.

有什么办法解决该问题吗?

Any ideas how to fix that?

推荐答案

所以您对我在评论中的意思有一个想法,这是一个潜在的答案

So you have an idea on what I meant in my comments here's a potential answer

由于您必须从不同的项目中加载不同的"config"文件并对其应用一些合并逻辑,因此我只避免使用默认"配置系统将JSON文件加载到应用程序中.相反,我会自己做.所以:

Since you have to load different "config" files from different projects and apply some merging logic to them, I would just avoid using the "default" configuration system to load the JSON files into the app. Instead, I would just do it myself. So:

  1. 读取JSON并将其反序列化为一种类型,并将其保留在列表中
  2. 浏览包含所有配置的列表并应用合并逻辑
  3. 将单个ServicesConfiguration注册为Singleton
  4. 删除您在Program.cs上拥有的代码以加载自定义JSON文件
  1. Read and deserialize the JSON into a type and keep it on a list
  2. Go through the list containing all configs and apply your merging logic
  3. Register the single ServicesConfiguration as a Singleton
  4. Remove the code you had on your Program.cs to load the custom JSON files

这是您的方法:

ServicesRootConfiguration(新类,以便能够反序列化json)

ServicesRootConfiguration (new class, to be able to deserialize the json)

public class ServicesRootConfiguration
{
    public ServicesConfiguration ServicesConfiguration { get; set; }
}

Startup.cs

public class Startup
{
    private readonly IHostingEnvironment _hostingEnvironment;

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        Configuration = configuration;
        _hostingEnvironment = env;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // other configuration omitted for brevity

        // build your custom configuration from json files
        var myCustomConfig = BuildCustomConfiguration(_hostingEnvironment);

        // Register the configuration as a Singleton
        services.AddSingleton(myCustomConfig);
    }

    private static ServicesConfiguration BuildCustomConfiguration(IHostingEnvironment env)
    {
        var allConfigs = new List<ServicesRootConfiguration>();

        var path = Path.Combine(env.ContentRootPath, "App_Config");

        foreach (var file in Directory.EnumerateFiles(path, "*.json", SearchOption.AllDirectories))
        {
            var config = JsonConvert.DeserializeObject<ServicesRootConfiguration>(File.ReadAllText(file));
            allConfigs.Add(config);
        }

        // do your logic to "merge" the each config into a single ServicesConfiguration
        // here I simply select the AssemblyName from all files.
        var mergedConfig = new ServicesConfiguration
        {
            Services = allConfigs.SelectMany(c => c.ServicesConfiguration.Services).ToList()
        };

        return mergedConfig;
    }
}

然后通常在您的Controller中通过DI获取实例.

Then in your Controller just normally get the instance by DI.

public class HomeController : Controller
{
    private readonly ServicesConfiguration _config;

    public HomeController(ServicesConfiguration config)
    {
        _config = config ?? throw new ArgumentNullException(nameof(config));
    }
}

使用这种方法,最终会得到与正常注册IOptions时相同的行为.但是,您避免依赖它,而不必使用uggly .Value(urgh).更好的是,您可以将其注册为接口,以便在测试/模拟过程中使您的生活更轻松.

With this approach, you ended up with the same behavior as you would get from normally registering the IOptions. But, you avoid having a dependency on it and having to use the uggly .Value (urgh). Even better, you could register it as an Interface so it makes your life easier during testing/mocking.

这篇关于如何从ASP.Net Core配置文件合并多个阵列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆