5

I am receiving this error whenever I try to deserialize the json string below:

Error:

Additional information: Error converting value "invalid_request_error" to type 'ErrorType'. Path 'type', line 2, position 33.

Json string

{
  "error": {
    "type": "invalid_request_error",
    "message": "Invalid request (check that your POST content type is application/x-www-form-urlencoded). If you have any questions, we can help at https://support.stripe.com/."
  }
}  

Code

private void btnDeserialize_Click(object sender, EventArgs e)
{
    var r = Components.JsonMapper.MapFromJson<Components.DTO.Error>(txtToDeserialize.Text, "error");
    txtDeserialized.Text = JsonConvert.SerializeObject(r);
}  

JsonMapper

public static class JsonMapper
{
    public static T MapFromJson<T>(string json, string parentToken = null)
    {
        var jsonToParse = string.IsNullOrEmpty(parentToken) ? json : JObject.Parse(json).SelectToken(parentToken).ToString();

        return JsonConvert.DeserializeObject<T>(jsonToParse);
    }
}  

Enum

public enum ErrorCode
{
    Default,

    [JsonProperty("invalid_number")]
    InvalidNumber,

    [JsonProperty("invalid_expiry_month")]
    InvalidExpiryMonth,

    [JsonProperty("invalid_expiry_year")]
    InvalidExpiryYear,

    [JsonProperty("invalid_cvc")]
    InvalidCvc,

    [JsonProperty("incorrect_number")]
    IncorrectNumber,

    [JsonProperty("expired_card")]
    ExpiredCard,

    [JsonProperty("incorrect_cvc")]
    IncorrectCvc,

    [JsonProperty("incorrect_zip")]
    IncorrectZip,

    [JsonProperty("card_declined")]
    CardDeclined,

    [JsonProperty("missing")]
    Missing,

    [JsonProperty("processing_error")]
    ProcessingError
}

public enum ErrorType
{
    Default,

    [JsonProperty("api_connection_error")]
    ApiConnectionError,

    [JsonProperty("api_error")]
    ApiError,

    [JsonProperty("authentication_error")]
    AuthenticationError,

    [JsonProperty("card_error")]
    CardError,

    [JsonProperty("invalid_request_error")]
    InvalidRequestError,

    [JsonProperty("rate_limit_error")]
    RateLimitError
}

I want to stick on using Enums rather than string.
What could be the good workaround for this?

1 Answer 1

4

You have a few issues:

  1. You need to use StringEnumConverter to serialize enums as strings.

  2. Rather than [JsonProperty("enum_name")] you need to use [EnumMember(Value = "enum_name")] to specify a remapped enum name. You might also want to add [DataContract] for full compatibility with the data contract serializer.

  3. Once you have parsed your JSON string into a JToken, it will be more efficient to deserialize it using JToken.ToObject() or JToken.CreateReader(). No need to serialize to a string then re-parse from scratch.

Thus your types should look like:

[DataContract]
public enum ErrorCode
{
    Default,

    [EnumMember(Value = "invalid_number")]
    InvalidNumber,

    [EnumMember(Value = "invalid_expiry_month")]
    InvalidExpiryMonth,

    [JsonProperty("invalid_expiry_year")]
    InvalidExpiryYear,

    [EnumMember(Value = "invalid_cvc")]
    InvalidCvc,

    [EnumMember(Value = "incorrect_number")]
    IncorrectNumber,

    [EnumMember(Value = "expired_card")]
    ExpiredCard,

    [EnumMember(Value = "incorrect_cvc")]
    IncorrectCvc,

    [EnumMember(Value = "incorrect_zip")]
    IncorrectZip,

    [EnumMember(Value = "card_declined")]
    CardDeclined,

    [EnumMember(Value = "missing")]
    Missing,

    [EnumMember(Value = "processing_error")]
    ProcessingError
}

public class Error
{
    public ErrorType type { get; set; }
    public string message { get; set; }
}

[DataContract]
public enum ErrorType
{
    Default,

    [EnumMember(Value = "api_connection_error")]
    ApiConnectionError,

    [EnumMember(Value = "api_error")]
    ApiError,

    [EnumMember(Value = "authentication_error")]
    AuthenticationError,

    [EnumMember(Value = "card_error")]
    CardError,

    [EnumMember(Value = "invalid_request_error")]
    InvalidRequestError,

    [EnumMember(Value = "rate_limit_error")]
    RateLimitError
}

And your mapper:

public static class JsonMapper
{
    private static JsonReader CreateReader(string json, string parentToken)
    {
        if (string.IsNullOrEmpty(parentToken))
            return new JsonTextReader(new StringReader(json));
        else
        {
            var token = JToken.Parse(json).SelectToken(parentToken);
            return token == null ? null : token.CreateReader();
        }
    }

    public static T MapFromJson<T>(string json, string parentToken = null)
    {
        var settings = new JsonSerializerSettings { Converters = new [] { new StringEnumConverter() } };
        using (var reader = CreateReader(json, parentToken))
        {
            if (reader == null)
                return default(T);
            return JsonSerializer.CreateDefault(settings).Deserialize<T>(reader);
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

You save my day! Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.