Exception when deserializing yaml file to property of abstract class using YamlDotNet

1

Using YamlDotNet, I'm trying to deserialize a yaml file with a nested object graph into a set of custom .net types. This works if I set the tree property to a simple PopulationBasicNode, but when I use the PopulationAndNode as shown in the example, a YamlException is thrown:

No node deserializer was able to deserialize the node into type PopulationTreeNode

I thought that using the following extension method of the deserializer builder would make the deserializer being able to resolve the type.

WithTagMapping("!and", typeof(PopulationAndNode))

I also tried registering a INodeTypeResolver, but I still get the same expeption.

WithNodeTypeResolver(new PopulationNodeResolver())
public class PopulationNodeResolver : INodeTypeResolver
    {
        public bool Resolve(NodeEvent nodeEvent, ref Type currentType)
        {
            if (nodeEvent.Tag == "!and")
            {
                currentType = typeof(PopulationAndNode);
                return true;
            }

            return false;
        }
    }
# a population
- id: some-id
  tree:
    !and
      - !basic
        someProperty: hello
      - !basic
        someProperty: world
public class Population
{
    public string Id { get; set; }
    public PopulationTreeNode Tree { get; set; }
}
public abstract class PopulationTreeNode
{
    public string Id { get; set; }
}
public class PopulationAndNode : PopulationTreeNode
{
    public IEnumerable<PopulationTreeNode> Children { get; set; }
}
public class PopulationBasicNode : PopulationTreeNode
{
    public string SomeProperty { get; set; }
}
var resourcePath = assembly.GetManifestResourceNames().Single(str => str.EndsWith(fileName));

using Stream stream = assembly.GetManifestResourceStream(resourcePath);
using StreamReader streamReader = new StreamReader(stream);
var fileContent = streamReader.ReadToEnd();

var deserializer = new DeserializerBuilder()
                .WithNamingConvention(CamelCaseNamingConvention.Instance)
                .WithTagMapping("!and", typeof(PopulationAndNode))
                .WithTagMapping("!basic", typeof(PopulationBasicNode))
                .Build();

var populations = deserializer.Deserialize<List<Population>>(fileContent);
YamlDotNet.Core.YamlException
  HResult=0x80131500
  Message=(Line: 34, Col: 9, Idx: 1055) - (Line: 35, Col: 7, Idx: 1066): No node deserializer was able to deserialize the node into type _.PopulationTreeNode, _, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  Source=YamlDotNet
  StackTrace:
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.<>c__DisplayClass3_0.<DeserializeValue>b__0(IParser r, Type t)
   at YamlDotNet.Serialization.NodeDeserializers.ObjectNodeDeserializer.YamlDotNet.Serialization.INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.<>c__DisplayClass3_0.<DeserializeValue>b__0(IParser r, Type t)
   at YamlDotNet.Serialization.NodeDeserializers.CollectionNodeDeserializer.DeserializeHelper(Type tItem, IParser parser, Func`3 nestedObjectDeserializer, IList result, Boolean canUpdate)
   at YamlDotNet.Serialization.NodeDeserializers.CollectionNodeDeserializer.YamlDotNet.Serialization.INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value)
   at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
   at YamlDotNet.Serialization.Deserializer.Deserialize(IParser parser, Type type)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](IParser parser)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](TextReader input)
   at YamlDotNet.Serialization.Deserializer.Deserialize[T](String input)
   at _() in _
c#
yaml
deserialization
yamldotnet
asked on Stack Overflow Jan 29, 2021 by Ledda • edited Jan 29, 2021 by greenjaed

1 Answer

0

You forgot to add children to your yaml doc:

# a population
- id: some-id
  tree: !and
    children:
      - !basic
        someProperty: hello
      - !basic
        someProperty: world

You don't need the custom NodeResolver either, btw.

answered on Stack Overflow Jan 29, 2021 by greenjaed • edited Jan 29, 2021 by greenjaed

User contributions licensed under CC BY-SA 3.0