将配置绑定到.NET Core 2.0中的对象图

我正在制作.NET Core 2.0应用程序,我需要对其进行配置。 我正在查看此文档 ,似乎在.NET Core 1.0中您可以这样做:

var appConfig = new AppSettings(); config.GetSection("App").Bind(appConfig); 

在.NET Core 1.1中,您可以:

 var appConfig = config.GetSection("App").Get(); 

但在.NET Core 2.0中既不存在Bind也不存在。 实现这一目标的新方法是什么?

谢谢,

玩笑

你仍然可以做这两件事。 由于您处于控制台应用程序中,并且因此可能不使用ASP.NET Core元数据包,因此您需要确保具有正确的依赖项。

要将配置绑定到对象,您需要Microsoft.Extensions.Configuration.Binder包。 然后,两种解决方案都应该正常工作。


顺便说一句。 即使您在控制台应用程序中,您仍然可以使用ASP.NET Core附带的dependency injection容器。 我个人发现设置起来非常简单,所以如果你仍然可以修改你的应用程序来使用它,那么它可能是值得的。 设置将如下所示:

 var configuration = new ConfigurationBuilder() .AddJsonFile("config.json", optional: false) .Build(); var services = new ServiceCollection(); services.AddOptions(); // add your services here services.AddTransient(); services.AddTransient(); // configure options services.Configure(configuration.GetSection("App")); // build service provider var serviceProvider = services.BuildServiceProvider(); // retrieve main application instance and run the program var program = serviceProvider.GetService(); program.Run(); 

然后,所有注册的服务都可以像在ASP.NET Core中一样使用依赖项。 然后,为了使用您的配置,您可以像IOptions一样注入IOptions类型。

直到今天我终于明白了,我仍然遇到了这个问题。

代码运行没有问题,但所有属性仍然为null,即使在绑定之后。 我这样做:

 public class AppSettings { public string MyProperty } 

事实certificate你必须这样做:

 public class AppSettings { public string MyProperty { get; set; } } 

它只适用于您的类具有属性而不是字段。 这对我来说并不清楚。

如果要在Startup期间注册配置,请将此添加到Startup.cs

 services.Configure(Configuration.GetSection("App")); 

然后,您可以通过注入IOptions<>的实例来访问它:

 private readonly AppSettings _appSettings; public MyClass(IOptions appSettings) { _appSettings = appSettings.Value; } 

为了更简单的配置,我创建了一个帮助程序类,它扫描配置对象以获取嵌套配置,然后尝试在已加载的程序集中查找相应的类,并使用给定的配置对其进行初始化。

appsettings.json:

 { "MyState": { "SomeSimpleValue": "Hello World", "MyTimeSpan": "00:15:00" } } 

MyStateOptions.cs

 // Class has same name as in appsettings.json with Options suffix. public class MyStateOptions { // Properties must be deserializable from string // or a class with a default constructor that has // only properties that are deserializable from string. public string SomeSimpleValue { get; set; } public DateTime MyTimeSpan { get; set; } } 

Startup.cs

 public class Startup { public IConfigurationRoot Configuration { get; } public Startup(IHostingEnvironment env) { // Create configuration as you need it... var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile(...) .AddEnvironmentVariables(); // Save configuration in property to access it later. Configuration = builder.Build(); } public void ConfigureServices(IServiceCollection services) { // Register all your desired services... services.AddMvc(options => ...); // Call our helper method services.RegisterOptions(Configuration); } } 

HelperClass.cs

 public static class IServiceCollectionExtensions { public static void RegisterOptions( this IServiceCollection services, IConfiguration configuration) { // Create all options from the given configuration. var options = OptionsHelper.CreateOptions(configuration); foreach (var option in options) { // We get back Options : IOptions var interfaces = option.GetType().GetInterfaces(); foreach (var type in interfaces) { // Register options IServiceCollection services.AddSingleton(type, option); } } } } 

OptionsHelper.cs

 public static class OptionsHelper { public static IEnumerable CreateOptions(IConfiguration configuration) { // Get all sections that are objects: var sections = configuration.GetChildren() .Where(section => section.GetChildren().Any()); foreach (var section in sections) { // Add "Options" suffix if not done. var name = section.Key.EndsWith("Options") ? section.Key : section.Key + "Options"; // Scan AppDomain for a matching type. var type = FirstOrDefaultMatchingType(name); if (type != null) { // Use ConfigurationBinder to create an instance with the given data. var settings = section.Get(type); // Encapsulate instance in "Options" var options = CreateOptionsFor(settings); } } } private static Type FirstOrDefaultMatchingType(string typeName) { // Find matching type that has a default constructor return AppDomain.CurrentDomain.GetAssemblies() .Where(assembly => !assembly.IsDynamic) .SelectMany(assembly => assembly.GetTypes()) .Where(type => type.Name == typeName) .Where(type => !type.IsAbstract) .Where(type => type.GetMatchingConstructor(Type.EmptyTypes) != null) .FirstOrDefault(); } private static object CreateOptionsFor(object settings) { // Call generic method Options.Create(TOptions options) var openGeneric = typeof(Options).GetMethod(nameof(Options.Create)); var method = openGeneric.MakeGenericMethod(settings.GetType()); return method.Invoke(null, new[] { settings }); } } 

完成所有这些工作之后,您可以在服务集合中拥有一个服务,该服务在其构造函数中需要一个IOptions并且您将获得它而无需显式配置您拥有的每个选项。 只需使用所需的服务和选项实例创建一个新项目。 将项目添加到主项目,并将所需的配置添加到appsettings.json。

ExampleService.cs

 public class MyExampleService { private readonly MyStateOptions _options; public MyExampleService(IOptions options) { _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); } }