绑定到 appsettings.json 中的空数组时为空 属性
Null property when binding to empty array in appsettings.json
我在使用 Options 模式时偶然发现了一个问题,当绑定到空 JSON 数组时,模型属性被设置为 null
。
appsettings.json:
{
"MyOptions": {
"Values": []
}
}
MyOptions.cs:
public sealed class MyOptions
{
public IEnumerable<string> Values { get; set; }
}
Startup.cs:
...
services.Configure<MyOptions>(
_configuration.GetSection(nameof(MyOptions));
...
以上配置成功构建并在需要时注入 IOptions<MyOptions>
,但是 Values
属性 设置为 null
而不是空枚举。这将导致以下代码抛出 NullReferenceException
:
public class MyService
{
public MyService(IOptions<MyOptions> options)
{
var values = options.Value.Values;
foreach (var val in values)
{
// Do something
}
}
}
这已作为 dotnet 存储库 (https://github.com/dotnet/extensions/issues/1341) 上的一个问题提出,尽管 MS 似乎已将其关闭为“按设计工作”。
是否有解决方法来防止 NullReferenceException
被抛出?
一种可能的解决方法是更改 MyOptions
class 以使用支持字段而不是自动属性,并在 getter 中将 null-coalescing operator 更改为 return 空 IEnumerable
:
public sealed class MyOptions
{
private IEnumerable<string> _values;
public IEnumerable<string> Values
{
get => _values ?? new List<string>();
set => _values = value;
}
}
我总是确保配置中的属性 class 分配了有意义的默认值:
public sealed class MyOptions
{
public IEnumerable<string> Values { get; set; } = Array.Empty<string>();
}
这样我就不必在每次使用我的配置对象时检查 null
或未配置的值。
我认为 MS 给出了“按设计工作”的正确答案。你永远记住墨菲定律——任何可能出错的事情都会出错。要创建健壮的代码,任何人都应该期望任何可为空 属性 的空值,无论它是如何初始化的。它总是可以在途中的某个地方变为空。所以我总是检查 null
if (options.Value.Values != null)
foreach (var val in options.Value.Values)
{
// Do something
} else ... return error;
我不知道我的选项对于这个应用程序有多重要,但我通常已经在启动时检查了 appdata 数据
var myOptions = Configuration.GetSection(nameof(MyOptions));
if (myOptions.Exists())
{
services.Configure<MyOptions>(myOptions);
services.AddScoped(typeof(MyService));
} else ... return error
我在使用 Options 模式时偶然发现了一个问题,当绑定到空 JSON 数组时,模型属性被设置为 null
。
appsettings.json:
{
"MyOptions": {
"Values": []
}
}
MyOptions.cs:
public sealed class MyOptions
{
public IEnumerable<string> Values { get; set; }
}
Startup.cs:
...
services.Configure<MyOptions>(
_configuration.GetSection(nameof(MyOptions));
...
以上配置成功构建并在需要时注入 IOptions<MyOptions>
,但是 Values
属性 设置为 null
而不是空枚举。这将导致以下代码抛出 NullReferenceException
:
public class MyService
{
public MyService(IOptions<MyOptions> options)
{
var values = options.Value.Values;
foreach (var val in values)
{
// Do something
}
}
}
这已作为 dotnet 存储库 (https://github.com/dotnet/extensions/issues/1341) 上的一个问题提出,尽管 MS 似乎已将其关闭为“按设计工作”。
是否有解决方法来防止 NullReferenceException
被抛出?
一种可能的解决方法是更改 MyOptions
class 以使用支持字段而不是自动属性,并在 getter 中将 null-coalescing operator 更改为 return 空 IEnumerable
:
public sealed class MyOptions
{
private IEnumerable<string> _values;
public IEnumerable<string> Values
{
get => _values ?? new List<string>();
set => _values = value;
}
}
我总是确保配置中的属性 class 分配了有意义的默认值:
public sealed class MyOptions
{
public IEnumerable<string> Values { get; set; } = Array.Empty<string>();
}
这样我就不必在每次使用我的配置对象时检查 null
或未配置的值。
我认为 MS 给出了“按设计工作”的正确答案。你永远记住墨菲定律——任何可能出错的事情都会出错。要创建健壮的代码,任何人都应该期望任何可为空 属性 的空值,无论它是如何初始化的。它总是可以在途中的某个地方变为空。所以我总是检查 null
if (options.Value.Values != null)
foreach (var val in options.Value.Values)
{
// Do something
} else ... return error;
我不知道我的选项对于这个应用程序有多重要,但我通常已经在启动时检查了 appdata 数据
var myOptions = Configuration.GetSection(nameof(MyOptions));
if (myOptions.Exists())
{
services.Configure<MyOptions>(myOptions);
services.AddScoped(typeof(MyService));
} else ... return error