未捕获数组中的配置绑定异常?

Configuration binding exception in array not catched?

配置中数组的异常未通过?!对于一维配置,这是有效的(如您所见 )。但是当使用更多维配置时,将忽略异常,如您在以下示例中所见:

appsettings.json

{
  "Value": 1,
  "ArrayValue": [
    { "Value":  0 }
  ]
}

Config.cs

class Config
{
  private int value;

  public int Value
  {
    get => this.value;
    set
    {
        if (value < 1)
            throw new NullReferenceException();     // ExceptionType only for testing purpose

        this.value = value;
    }
  }

  public IEnumerable<ConfigArray> ArrayValue { get; set; }
}

class ConfigArray
{
  private int arrayValue;

  public int ArrayValue
  {
    get => this.arrayValue;
    set
    {
        if (value < 1)
            throw new NullReferenceException();     // ExceptionType only for testing purpose

        this.arrayValue = value;
    }
  }
}

程序片段

Config config;

try
{
    IConfigurationRoot configuration = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", false, false)
        .Build();

    config = configuration.Get<Config>();
    //config = new Config();
    //configuration.Bind(config);
}
catch (Exception ex)
{
    Console.WriteLine($"Exception: {ex.Message}");
}

<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />

ConfigArray 中的异常没有绕过主程序。我是否遗漏了什么或者数组中的异常通常被配置活页夹忽略?

我找到的一个可能的解决方案是创建一个 属性 来确定是否发生错误。

可能的解决方案:

Config.cs

// If more than one error is possible, it can be a better solution to generate error codes
enum ErrorCode
{
  OK,
  ERROR
}

class Config
{
  private int value;
  private IEnumerable<ConfigArray> configArray;

  public int Value
  {
    get => this.value;
    set
    {
      if (value < 1)
        throw new NullReferenceException();     // ExceptionType only for testing purpose

      this.value = value;
    }
  }


  public IEnumerable<ConfigArray> ArrayValue
  {
    get => this.configArray;
    set
    {
      value.ToList().ForEach(c =>
      {
        switch (c.Error)
        {
          case ErrorCode.ERROR:
            throw new NullReferenceException();
          default:
            break;
        }   
      });

      this.configArray = value;
    }
  }
}

class ConfigArray
{
  private int arrayValue;

  public int ArrayValue
  {
    get => this.arrayValue;
    set
    {
      this.Error = ErrorCode.OK;

      if (value < 1)
        this.Error = ErrorCode.ERROR;

      this.arrayValue = value;
    }
  }

  public ErrorCode Error { get; private set; }
}

程序片段

Config config = null;

try
{
  IConfigurationRoot configuration = new ConfigurationBuilder()
      .SetBasePath(Directory.GetCurrentDirectory())
      .AddJsonFile("appsettings.json", false, false)
      .Build();

  config = configuration.Get<Config>();
  //config = new Config();
  //configuration.Bind(config);
}
catch (Exception ex)
{
  if(ex.InnerException is Exception)
      Console.WriteLine($"Inner Exception: {ex.InnerException.Message}");

  Console.WriteLine($"Exception: {ex.Message}");
}

也许有更好的解决方案?

有关详细信息,请参阅此处。 Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs

private static Array BindArray(Array source, IConfiguration config, BinderOptions options)
{
    IConfigurationSection[] children = config.GetChildren().ToArray();
    int arrayLength = source.Length;
    Type elementType = source.GetType().GetElementType();
    var newArray = Array.CreateInstance(elementType, arrayLength + children.Length);

    // binding to array has to preserve already initialized arrays with values
    if (arrayLength > 0)
    {
        Array.Copy(source, newArray, arrayLength);
    }

    for (int i = 0; i < children.Length; i++)
    {
        try
        {
            object item = BindInstance(
                type: elementType,
                instance: null,
                config: children[i],
                options: options);
                
            if (item != null)
            {
                newArray.SetValue(item, arrayLength + i);
            }
        }
        catch
        {
        }
    }

    return newArray;
}

正如您在上面的代码中看到的,我们捕获并控制了异常。 因此,有必要像sunriax.

那样采取行动