New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exception during deserialization of nullable enum >= YamlDotNet v9.1.0 #544
Comments
That's not intended. Thanks for reporting this issue. I haven't looked into it yet, but there was a change recently to handle billable types - #539. Maybe the bug was introduced there. |
Does brake our projects as well:
|
I am also experiencing this on version 9.1.0 with .NET 5.0.0. # µblog API settings
# Public URL
# Publicly exposed URL for your µblog site
publicUrl: "http://localhost:5000"
# Allowed Hosts
# List of hosts allowed to connect to API server directly
allowedHosts: "*"
# Serilog Configuration
# Configuration for logging with Serilog
# https://github.com/serilog/serilog-settings-configuration
serilog:
using:
- "Serilog.Sinks.Console"
# - "Serilog.Sinks.File"
writeTo:
- name: "Console"
# - Name: "File"
# Args:
# path: "Logs/log.txt"
enrich:
- "FromLogContext"
properties:
application: "µblog-server" |
The issue seems to be that it checks if the type is an enum before unwrapping a nullable type. When the enum type check fails, it uses Perhaps it should unwrap the nullable type first. var underlyingType = Nullable.GetUnderlyingType(expectedType) ?? expectedType;
if (underlyingType.IsEnum())
{
value = Enum.Parse(underlyingType, scalar.Value, true);
}
else
{
var typeCode = underlyingType.GetTypeCode(); |
Hello, I noticed that we are also experiencing that issue when I tried to upgrade from 8.1.2 to 9.1.0 Hope it gets fixed soon |
Here is a simple workaround I wrote: public class YamlNullableEnumTypeConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return Nullable.GetUnderlyingType(type)?.IsEnum ?? false;
}
public object ReadYaml(IParser parser, Type type)
{
type = Nullable.GetUnderlyingType(type) ?? throw new ArgumentException("Expected nullable enum type for ReadYaml");
var scalar = parser.Consume<Scalar>();
if (string.IsNullOrWhiteSpace(scalar.Value))
{
return null;
}
try
{
return Enum.Parse(type, scalar.Value);
}
catch(Exception ex)
{
throw new Exception($"Invalid value: \"{scalar.Value}\" for {type.Name}", ex);
}
}
public void WriteYaml(IEmitter emitter, object value, Type type)
{
type = Nullable.GetUnderlyingType(type) ?? throw new ArgumentException("Expected nullable enum type for WriteYaml");
if (value != null)
{
var toWrite = Enum.GetName(type, value) ?? throw new InvalidOperationException($"Invalid value {value} for enum: {type}");
emitter.Emit(new Scalar(null, null, toWrite, ScalarStyle.Any, true, false));
}
}
} |
@Trojaner - I improved your workaround slightly so it handles more null literal cases, and does a case-insensitive enum parse (as is the default in YamlDotNet). private class YamlNullableEnumTypeConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return Nullable.GetUnderlyingType(type)?.IsEnum ?? false;
}
public object ReadYaml(IParser parser, Type type)
{
type = Nullable.GetUnderlyingType(type) ?? throw new ArgumentException("Expected nullable enum type for ReadYaml");
if (parser.Accept<NodeEvent>(out var @event))
{
if (NodeIsNull(@event))
{
parser.SkipThisAndNestedEvents();
return null;
}
}
var scalar = parser.Consume<Scalar>();
try
{
return Enum.Parse(type, scalar.Value, ignoreCase: true);
}
catch (Exception ex)
{
throw new Exception($"Invalid value: \"{scalar.Value}\" for {type.Name}", ex);
}
}
public void WriteYaml(IEmitter emitter, object value, Type type)
{
type = Nullable.GetUnderlyingType(type) ?? throw new ArgumentException("Expected nullable enum type for WriteYaml");
if (value != null)
{
var toWrite = Enum.GetName(type, value) ?? throw new InvalidOperationException($"Invalid value {value} for enum: {type}");
emitter.Emit(new Scalar(null, null, toWrite, ScalarStyle.Any, true, false));
}
}
private static bool NodeIsNull(NodeEvent nodeEvent)
{
// http://yaml.org/type/null.html
if (nodeEvent.Tag == "tag:yaml.org,2002:null")
{
return true;
}
if (nodeEvent is Scalar scalar && scalar.Style == ScalarStyle.Plain)
{
var value = scalar.Value;
return value is "" or "~" or "null" or "Null" or "NULL";
}
return false;
}
} |
There is a PR that should fix this issue. I have published a pre-release version containing this fix, named |
I can confirm it works in GitVersion |
Apparently this issue got closed automatically, so I'm reopening it. |
Confirming it works for me as well. |
@aaubry The fix works for PSRule as well. |
Thanks to everyone who took the time to test. A release that includes this fix is currently building. |
A fix for this issue has been released in version 11.1.1. |
Problem deserializing nullable enum with YamlDotNet v9.1.0, no issue on v8.1.2.
Is this intended?
The text was updated successfully, but these errors were encountered: