将false反序列化为null(System.Text.Json)

5
我正在使用一个API,但它在应该使用null的地方却使用了false。我无法正确反序列化此内容。我尝试创建自定义JsonConverter来解决此问题,但未能成功。我想避免使用动态类型。请问该如何反序列化?
这是默认响应。
{
    "products": [
        {
            "id": 123456789,
            "supplier": {
                "id": 123456,
                "title": "abc"
            }
        }
    ]
}

我将其按照以下方式进行反序列化。
public class Container
{
    public Product[] products { get; set; }
}

public class Product
{
    public ulong id { get; set; }
    public Supplier supplier { get; set; }
}

public class Supplier
{
    public ulong id { get; set; }
    public string title { get; set; }
}

JsonSerializer.Deserialize<Container>(json)

当产品没有供应商时,返回该响应。

{
    "products": [
        {
            "id": 123456789,
            "supplier": false
        }
    ]
}

为了做到正确,这里的问题是API端点返回false,而应该返回null,还是你无法反序列化序列化的对象? - vasilisdmr
@vasilisdmr 问题在于我无法反序列化已序列化的对象。不幸的是,我无法改变API的行为。 - Pete
请查看微软文档中的以下文章,其中提到“不支持对没有无参构造函数的引用类型进行反序列化” https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to#deserialization-behavior - vasilisdmr
@Pete,你能否使用我下面的建议解决你的问题?https://dev59.com/7rnoa4cB1Zd3GeqPWb0e#60642484 - ahsonkhan
3个回答

4
您可以为 supplier 属性创建自定义的 JsonConverter
public class Product
{
    public ulong id { get; set; }

    [JsonConverter(typeof(SupplierConverter))]
    public Supplier supplier { get; set; }
}

public class SupplierConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
       if (reader.TokenType == JsonToken.Boolean)
       {
           if ((bool)reader.Value == false)
               return null;
       }

       return serializer.Deserialize(reader, objectType);
    }

    public override bool CanConvert(Type objectType)
    {
        return false;
    }
}

更新:

如果您使用的是System.Text.Json,您可以尝试以下自定义转换器:

public class SupplierConverter : JsonConverter<Supplier>
{
    public override Supplier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.False)
            return null;

        if (options.GetConverter(typeof(JsonElement)) is JsonConverter<JsonElement> converter)
        {
            var json = converter.Read(ref reader, typeToConvert, options).GetRawText();

            return JsonSerializer.Deserialize<Supplier>(json);
        }

        throw new JsonException();
    }

    public override void Write(Utf8JsonWriter writer, Supplier value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

这似乎是针对Json.NET的。我正在使用System.Text.Json。 - Pete
@tzrm,你的示例转换器编写方式会导致stackoverflow,并且做了一些不必要的工作(https://dotnetfiddle.net/1yqrZ5)。你应该通过选项注册转换器,然后在转换器中不传递选项,或者完全在转换器中处理Supplier转换。以下是两种你应该考虑编写和使用它的方式:https://dotnetfiddle.net/XFbXB1 - ahsonkhan

3
当使用System.Text.Json时,您可以为Supplier属性实现并注册自己的JsonConverter<T>
根据您的需求(是否需要在多个地方使用Supplier对象或者是否需要使用不同的JsonSerializerOption设置),有两种方法可以考虑实现转换器。
  1. 创建一个JsonConverter<Supplier>,并添加处理false的自定义逻辑。其余部分由Deserialize调用处理。在您的实现中,请不要传递选项。然后,在选项中注册此转换器。这是最简单的方法。
// Don't register this converter using an attribute on the Supplier class 
// since you are calling Deserialize on this type directly within the converter.
public class SupplierConverter : JsonConverter<Supplier>
{
    public override Supplier Read(
        ref Utf8JsonReader reader, 
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.False)
        {
            return null;
        }

        // Skip passing options here to avoid stackoverflow
        // This approach won't work if you have other options that need to be honored
        // when deserializing Supplier.
        return JsonSerializer.Deserialize<Supplier>(ref reader);
    }

    public override void Write(
        Utf8JsonWriter writer, 
        Supplier value, 
        JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

// Register the converter within options as follows
// and pass the options the JsonSerializer.Deserialize call.
var options = new JsonSerializerOptions
{
    Converters = {new SupplierConverter()}
};
  1. 或者,创建一个JsonConverter<Supplier>并添加自定义逻辑来处理"false"以及对Supplier对象进行反序列化。在这种情况下,您可以将此转换器注册在选项中,也可以将其用作Supplier类本身的属性。如果您需要使用自定义选项设置来反序列化供应商(例如属性名称不区分大小写的匹配),请遵循此方法。
public class SupplierConverter : JsonConverter<Supplier>
{
    public override Supplier Read(
        ref Utf8JsonReader reader, 
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        // Put whatever special case condition here. 
        // I added a null token check as well, just in case.
        if (reader.TokenType == JsonTokenType.False 
            || reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        var output = new Supplier();

        // Potentially add other error handling for invalid JSON, if needed.
        while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
        {
            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                if (reader.ValueTextEquals("id"))
                {
                    if (!reader.Read()) throw new JsonException();
                    output.id = reader.GetUInt64();
                }
                else if (reader.ValueTextEquals("title"))
                {
                    if (!reader.Read()) throw new JsonException();
                    output.title = reader.GetString();
                }
            }
        }

        if (reader.TokenType != JsonTokenType.EndObject)
        {
            throw new JsonException();
        }

        return output;
    }

    public override void Write(
        Utf8JsonWriter writer, 
        Supplier value, 
        JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

// Register the converter within options as follows
// and pass the options the JsonSerializer.Deserialize call.
var options = new JsonSerializerOptions
{
    Converters = {new SupplierConverter()}
};

// OR
// Use annotate your Supplier class with
// a JsonConverterAttribute.

当您编写自定义转换器时,本文档将对您有所帮助:

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to

这里是相关的API文档:

这是一个工作示例(当JSON包含false供应商和实际的supplier JSON对象时均适用):https://dotnetfiddle.net/XFbXB1


-3

假设您正在使用Json.Net

var settings = new JsonSerializerSettings();
        settings.NullValueHandling = NullValueHandling.Include;
        settings.DefaultValueHandling = DefaultValueHandling.Include;


JsonSerializer.Deserialize<Container>(json,settings)

或者尝试

var serializeOptions = new JsonSerializerOptions
{
    IgnoreNullValues =false
};

 JsonSerializer.Deserialize<Container>(json,serializeOptions)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接