【问题标题】:How do you bind a new options object in .NET Core 3.1?如何在 .NET Core 3.1 中绑定新的选项对象?
【发布时间】:2020-08-10 09:24:33
【问题描述】:

我正在尝试使用 ASP.NET Core 3.1 和选项模式在 C# 中编写扩展方法,该方法可以绑定提供程序中提供的任何现有配置(例如 appsettings.json),或者如果没有找到现有配置则绑定改为配置的默认对象。

我的目标是允许开发人员选择在 appsettings.json 中包含他们自己的自定义配置,或者只使用默认选项。

我遇到的问题是,当我尝试将对象SomeOptions 绑定到配置对象,然后尝试通过调用Configuration.GetSection("SomeOptions").Get<SomeOptions>() 检索IOptions<SomeOptions> 时,它总是返回一个空对象。

例如:

// Binding the creating options object to the configuration
var someOptions = new SomeOptions();
var section = Configuration.GetSection("SomeOptions")
section.Bind(someOptions);

// Retrieve the IOptions<SomeOptions> from the configuration
// This is the problem - it always returns null
var retrievedOptions = section.Get<SomeOptions>();

为什么新创建的对象没有绑定到配置?

这是我写的函数:

/// <summary>
/// Adds options to the <see cref="IServiceCollection"/> injected services.
/// If no options can be found within configuration then the default options will be used.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the option bindings to.</param>
/// <param name="configuration">The <see cref="IConfiguration"/> object used to retrieve the configuration sections from.</param>
/// <param name="sectionName">
/// The name of the configuration section to bind the options with.
/// If the configuration section cannot be found or it's blank the default configuration will be used instead.
/// </param>
/// <returns>The originally passed <see cref="IServiceCollection"/> with the added options.</returns>
public static IServiceCollection AddTransientOptionsWithDefault<TOptions>(this IServiceCollection services, IConfiguration configuration, string sectionName)
     where TOptions : class, new()
{
    if (configuration == null)
    {
        throw new ArgumentNullException(nameof(configuration));
    }

    // Retrieve any configured options
    var section = configuration.GetSection(sectionName);

    // If no configuration was found use the default options
    var options = section.Get<TOptions>();
    if (options == null)
    {
        options = new TOptions();

        // This section here seems to be the issue.
        // These are all of the different binding methods I've tried.
        section.Bind(options);
        //configuration.GetSection(sectionName).Bind(options);
        //services.Configure<TOptions>(configureOptions => new TOptions());
        //configuration.Bind(options);
    }

    // This returns null as it can't find the added TOptions
    var newSection = configuration.GetSection(sectionName).Get<TOptions>();

    // Another example - this returns an empty list
    var sectionChildren = section.GetChildren();

    services.Configure<TOptions>(section);

    return services;
}

示例选项对象:

public class CorsOptions
{
    public string[] Origins { get; set; } = Array.Empty<string>();
}

appsettings.json:

{
    "Cors": {
        "Origins": [ "www.google.com" ]
    }
}

以上所有内容在现实世界中的使用示例...

Startup.cs sn-p:

private IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    AddCorsWithOrigins(services, Configuration);
}

private IServiceCollection AddCorsWithOrigins(IServiceCollection services, IConfiguration configuration)
{
    // The idea here is that any "Cors" configuration will be used if it exists,
    // otherwise it will just add the default IOptions<CorsOptions> instead
    services.AddTransientOptionsWithDefault<CorsOptions>(configuration, "Cors");

    // Retrieve the options that have been added to the configuration
    var corsOptions = configuration.GetSection("Cors");

    // Do something with the corsOptions object that has been added...
}

【问题讨论】:

  • I'm able to unable to bind a newly created object to the IServices/IConfiguration object to be later retrieved through a standard Configuration.GetSection("SomeName").Get() 能否进一步说明问题?
  • 我已经用一个更好的问题示例更新了这个问题
  • 我们可以查看您的默认 SomeOptions 实例吗?你在哪里设置它的默认值?
  • 我添加了更详细的配置、选项以及如何在实际解决方案中发挥作用的更好示例。
  • 嗨。只是一个善意的提醒。在这种情况下仍然没有公认的答案,你需要别的吗?

标签: c# asp.net-core asp.net-core-3.1


【解决方案1】:

确保导入包 Microsoft.Extensions.Options.ConfigurationExtensions。 完成此操作后,您可以将其绑定到您的自定义 Dto 类。我在下面尝试过:

serviceCollection.Configure(configuration.GetSection("Global")); 其中 AppSettingDto 是我的自定义类,Global 是我的 appsettings json 文件中的一个部分

public class AppSettingDto
{
    public bool UseSendGrid { get; set; }
    public string EmailFrom { get; set; }
}

"Global": {
"EmailFrom": "sunnylnct007@gmail.com",
"UseSendGrid": true
},

以下是帮助我解决问题的 github 链接 https://github.com/dotnet/AspNetCore.Docs/issues/18833

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多