我想在我的应用程序中动态加载和注册服务。为此,我需要能够从解决方案中的不同项目加载配置文件,并将它们中的值合并到单个 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>();
Run Code Online (Sandbox Code Playgroud)
该代码*.json
在App_Config\Include
目录中搜索所有带有扩展名的文件,并将它们全部添加到配置生成器中。
文件的结构如下所示:
{
"ServicesConfiguration": {
"Services": [
{
"AssemblyName": "ParsingEngine.ServicesConfigurator, ParsingEngine"
}
]
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我得到了主要部分,ServicesConfiguration
然后Services
用具有一个属性的对象数组AssemblyName
。
要读取这些值,我使用ServicesConfiguration
带列表的类:
public class ServicesConfiguration
{
public List<ServiceAssembly> Services { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
该列表使用ServiceAssembly
类:
public class ServiceAssembly
{
public string AssemblyName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
要加载我IOptions
在构造函数级别 (DI)使用的配置:
Microsoft.Extensions.Options.IOptions<ServicesConfiguration> servicesConfiguration,
Run Code Online (Sandbox Code Playgroud)
并且配置似乎已加载 - 但文件中的值并未合并,而是被上次找到的文件覆盖。
任何想法如何解决这个问题?
所以你对我在评论中的意思有一个想法,这是一个潜在的答案
由于您必须从不同的项目加载不同的“配置”文件并对它们应用一些合并逻辑,因此我将避免使用“默认”配置系统将JSON
文件加载到应用程序中。相反,我只会自己做。所以:
ServicesConfiguration
为Singleton
Program.cs
加载自定义JSON
文件的代码你可以这样做:
ServicesRootConfiguration
(新类,能够反序列化json)
public class ServicesRootConfiguration
{
public ServicesConfiguration ServicesConfiguration { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在您Controller
通常通过 DI 获取实例。
public class HomeController : Controller
{
private readonly ServicesConfiguration _config;
public HomeController(ServicesConfiguration config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
}
}
Run Code Online (Sandbox Code Playgroud)
使用这种方法,您最终会得到与通常注册IOptions
. 但是,您可以避免依赖它并避免使用 uggly .Value
(urgh)。更好的是,您可以将其注册为接口,以便在测试/模拟期间使您的生活更轻松。
归档时间: |
|
查看次数: |
2998 次 |
最近记录: |