简体   繁体   English

绑定到 appsettings.json 中的空数组时为空属性

[英]Null property when binding to empty array in appsettings.json

I stumbled across an issue when using the Options pattern where model properties are being set to null when bound to an empty JSON array.我在使用Options模式时偶然发现了一个问题,其中模型属性在绑定到一个空的 JSON 数组时被设置为null

appsettings.json : appsettings.json

{
  "MyOptions": {
    "Values": []
  }
}

MyOptions.cs :我的选项.cs

public sealed class MyOptions
{
  public IEnumerable<string> Values { get; set; }
}

Startup.cs :启动.cs

...
services.Configure<MyOptions>(                            
  _configuration.GetSection(nameof(MyOptions));
...

The above configuration successfully builds and injects an IOptions<MyOptions> when required, however Values property is set to null rather than an empty enumerable.上述配置成功构建并在需要时注入IOptions<MyOptions> ,但是Values属性设置为null而不是空的可枚举。 This would cause the following code to throw a NullReferenceException :这将导致以下代码抛出NullReferenceException

public class MyService
{
  public MyService(IOptions<MyOptions> options)
  {
    var values = options.Value.Values;

    foreach (var val in values)
    {
      // Do something
    }
  }
}

This has been raised as an issue on the dotnet repo ( https://github.com/dotnet/extensions/issues/1341 ) although MS seem to have closed it as "working as designed".这已作为 dotnet 存储库 ( https://github.com/dotnet/extensions/issues/1341 ) 上的一个问题提出,尽管 MS 似乎已将其关闭为“按设计工作”。

Is there a workaround to prevent the NullReferenceException being thrown?是否有防止抛出NullReferenceException的解决方法?

One possible workaround is to alter the MyOptions class to use backing fields instead of auto-properties and in the getter a null-coalescing operator to return an empty IEnumerable :一种可能的解决方法是更改MyOptions类以使用支持字段而不是自动属性,并在 getter 中使用空合并运算符返回空IEnumerable

public sealed class MyOptions
{
  private IEnumerable<string> _values;

  public IEnumerable<string> Values
  {
    get => _values ?? new List<string>();
    set => _values = value;
  }
}

I always make sure my properties inside a configuration class have meaningful default values assigned:我总是确保我在配置类中的属性分配了有意义的默认值:

public sealed class MyOptions
{
  public IEnumerable<string> Values { get; set; } = Array.Empty<string>();
}

This way I don't have to check for null or not configured values each time I'm using my configuration object.这样我就不必在每次使用我的配置对象时检查null或未配置的值。

I think that MS gave a right answer "working as designed".我认为 MS 给出了“按设计工作”的正确答案。 You have allways remember Murphy's Law - anything that can go wrong will go wrong.你一直都记得墨菲定律——任何可能出错的事情都会出错。 To create the robust code anyone should expect null value for any nullable property, doesn't matter how it was init.为了创建健壮的代码,任何人都应该期望任何可空属性的空值,不管它是如何初始化的。 It can always became null somewhere on the way.它总是可以在途中的某个地方变为空。 So I am always checking for null所以我总是检查 null

  if (options.Value.Values != null)
    foreach (var val in options.Value.Values)
    {
       // Do something
    } else ... return error;
       

I don' t know how myoptions are important for this application, but I usually check appdata data in startup already我不知道 myoptions 对这个应用程序有多重要,但我通常已经在启动时检查 appdata 数据

var myOptions = Configuration.GetSection(nameof(MyOptions));
if (myOptions.Exists())
{
    services.Configure<MyOptions>(myOptions);
    services.AddScoped(typeof(MyService));
} else ... return error

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM