c# - 如何从 ASP.Net Core 配置文件中合并多个数组?

标签 c# asp.net-core

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

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

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 的文件,并将它们全部添加到配置构建器中。

文件结构如下所示:

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

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

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

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

并且该列表使用 ServiceAssembly 类:

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

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

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

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

有什么解决办法吗?

最佳答案

所以您对我在评论中的意思有所了解,这是一个可能的答案

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

  1. 读取 JSON 并将其反序列化为一种类型并将其保存在列表中
  2. 浏览包含所有配置的列表并应用您的合并逻辑
  3. 将单个 ServicesConfiguration 注册为 Singleton
  4. 删除您在 Program.cs 上的代码以加载自定义 JSON 文件

这里是你如何做到的:

ServicesRootConfiguration(新类,能够反序列化 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 获取实例。

public class HomeController : Controller
{
    private readonly ServicesConfiguration _config;

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

使用这种方法,您最终会得到与正常注册 IOptions 相同的行为。但是,您避免了对它的依赖并且不得不使用丑陋的 .Value (呃呃)。更好的是,您可以将其注册为接口(interface),以便在测试/模拟期间让您的生活更轻松。

关于c# - 如何从 ASP.Net Core 配置文件中合并多个数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53985133/

相关文章:

asp.net-core - "Failed to launch debug adapter"将 x86 与 Blazor 一起使用时

c# - 在 Windows 窗体应用程序中动态增加/减少视频的速度

asp.net-core - 我们可以将 Mvc 应用程序开发的 .Net 框架转换为 Mvc Asp.Net Core 2.0 而无需更改代码或更改最少的代码

c# - VS2012 导出 "User Settings"

c# - 我是否干净地编写了这个异常处理?

c# - asp.net 核心默认代理

logging - ASP.NET Core 1.0 日志记录

javascript - asp core 和 angular7 中没有 'Access-Control-Allow-Origin' header

c# - "Procedure or function has too many arguments specified"但它没有

c# - 将日期时间从 iPhone 应用程序发送到网络服务