Click here to Skip to main content
15,347,117 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
C#
public enum SaleType
{
    [EnumMember(Value = "COD")]
    COD,
    [EnumMember(Value = "ONLINE")]
    ONLINE,
    [EnumMember(Value = "PICKUP")]
    PICKUP,
    [EnumMember(Value = "OTHER")]
    OTHER
}
public class Order
{
    public SaleType saletype { get; set; }
    public int itemid { get; set; }
}

public class Config
{
    public string State { get; set; }
    public decimal Price { get; set; }
    public decimal? discount { get; set; }
    public Order Order { get; set; }
}

public class Root
{
    public Config Config { get; set; }
}


{
    "Config": {
        "State": "combodia",
        "Price": "28.78",
        "discount": "",
        "Order": {
            "saletype": "PICKUP",
            "itemid": "2"
        }
    }
}


What I have tried:

Above are my C# class and JSON request model data for API.

this JSON data throwing validation error for below properties.
Order.saletype -- (Enum type) JSON has string value of ENUM property, if I pass integer it is working. but for string there is validation error.

price --(decimal) JSON has string value. how do I handle this, I can not demand to client to send in decimal format.
Discount--(decimal nullable type), JSON request data has empty string, it throws error, If I pass any decimal value/ null, then it works fine.

How to handle this request model validation?


I have tried this to handle enum string validation issue, but still no use
C#
[JsonConverter(typeof(JsonStringEnumConverter))]
Posted
Updated 9-May-22 3:51am
v2
Comments
Graeme_Grant 9-May-22 7:44am
   
Are you trying to encode or decode? Also, are you using NewtonSoft or System.Text.Json ?

"type mismatch during model binding"

Firstly, Price value here is a string:
"Price": "28.78",

Yet you define you proerty in your class as a decimal type.

Yes you have a "type mismatch" error. The error message is very explicit:
Message=The JSON value could not be converted to System.Nullable`1[System.Decimal]. Path: $.Config.Price | LineNumber: 3 | BytePositionInLine: 24.

You will need to write a custom converter to convert between value types. The alternative, if possible, is to correctly serialize the value as a number. This is the prefered option if possible. It should look like this:
"Price": 28.78,

Here is how to write a custom converter for the System.Text.Json namespace. Newtownsoft Custom Converters are a little bit different - you can learn more here: Working with JSON in C# & VB[^]
C#
public class StringToDecimalConverter : JsonConverter<decimal>
{
    public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        decimal.TryParse(reader.GetString()!, out decimal value);
        return value;
    }

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

There are two ways that you can use the Custom Converter:
1. JsonSerializerOptions
2. As a Property Atteribute.

You can read more about Custom Converters here: How to write custom converters for JSON serialization - .NET | Microsoft Docs[^] - there are how-to examples.

Here we will use Property Attributes:
C#
public class Config
{
    public string? State { get; set; }

    [JsonConverter(typeof(StringToDecimalConverter))]  
    public decimal? Price { get; set; }

    [JsonConverter(typeof(StringToDecimalConverter))]  
    public decimal? discount { get; set; }

    public Order? Order { get; set; }
}

Now the Price and discount properties will not throw errors.

The next issue that you have is your saletype property. This will throw a similar error as you cannot convert String to Enum. Luckily, there is a pre-built JsonStringEnumConverter class. You can read more here: https://docs.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonstringenumconverter?view=net-6.0[^]. This is staight forward to use:
C#
public enum SaleType
{
    COD,
    ONLINE,
    PICKUP,
    OTHER
}

public class Order
{
    [JsonConverter(typeof(JsonStringEnumConverter))]  
    public SaleType? saletype { get; set; }
}

The last issue that you have is your Order.itemid property. You can not convert a string to an int. I have written the StringToDecimalConverter converter for you, StringToIntegerConverter I will leave to you.

** UPDATE **

For Completeness, here is my test code:

1. Program.cs (dot net 6.0)
C#
using System.Diagnostics;
using System.Text.Json;

string json =
    @"{
    ""Config"": {
        ""State"": ""combodia"",
        ""Price"": ""28.78"",
        ""discount"": """",
        ""Order"": {
            ""saletype"": ""PICKUP""
        }
    }
}";

var data = JsonSerializer.Deserialize<Root>(json);

Debugger.Break();

2. Classes used:
C#
using System.Text.Json.Serialization;

public enum SaleType
{
    COD,
    ONLINE,
    PICKUP,
    OTHER
}

public class Order
{
    [JsonConverter(typeof(JsonStringEnumConverter))]  
    public SaleType? saletype { get; set; }
    
    //public int? itemid { get; set; }
}

public class Config
{
    public string? State { get; set; }

    [JsonConverter(typeof(StringToDecimalConverter))]  
    public decimal? Price { get; set; }

    [JsonConverter(typeof(StringToDecimalConverter))]  
    public decimal? discount { get; set; }

    public Order? Order { get; set; }
}

public class Root
{
    public Config? Config { get; set; }
}

public class StringToDecimalConverter : JsonConverter<decimal>
{
    public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        decimal.TryParse(reader.GetString()!, out decimal value);
        return value;
    }

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

Code runs and deserializes successfully.
   
v4
See this page for docs on JsonConverters.

For the price, I guess your converter should try to parse whatever is passed in to a decimal and if it can't be done return a default? For discount check for an empty string and return 0.00, presumably.
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900