Vonage / vonage-dotnet-sdk

Vonage REST API client for .NET, written in C#. API support for SMS, Voice, Text-to-Speech, Numbers, Verify (2FA) and more.
https://developer.vonage.com/
Apache License 2.0
106 stars 86 forks source link

StartTime is not nullable in class Completed (EventWebHook) #576

Closed MarcusKohnert closed 5 months ago

MarcusKohnert commented 6 months ago

Describe the bug I'm using the EventBase.ParseEvent method to parse the received webhook events.

Expected behaviour: The method is able to parse a Completed event send by Vonage.

{
    "start_time": null,
    "headers": {
        "[redacted]": "[redacted]"
    },
    "rate": null,
    "from": "[redacted]",
    "to": "[redacted]",
    "uuid": "7d68ace9-29e3-4e8f-8611-5c97a16716e8",
    "conversation_uuid": "CON-baea4930-4c98-4cd6-b733-d5711157ffe9",
    "status": "completed",
    "direction": "outbound",
    "network": null,
    "timestamp": "2024-04-24T14:16:32.115Z"
}

Actual behaviour: EventBase.ParseEvent throws an exception because start_time is null and StartTime is of type DateTime (which is not nullable).

StackTrace

Newtonsoft.Json.JsonSerializationException
  HResult=0x80131500
  Message=Error converting value {null} to type 'System.DateTime'. Path 'start_time', line 1, position 18.
  Source=Newtonsoft.Json
  StackTrace:
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Vonage.Voice.EventWebhooks.EventBase.DeserializeStatus(String json, JProperty statusProperty)
   at Vonage.Voice.EventWebhooks.EventBase.ParseEvent(String json)

  This exception was originally thrown at this call stack:
    System.Convert.ChangeType(object, System.Type, System.IFormatProvider)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(Newtonsoft.Json.JsonReader, object, System.Globalization.CultureInfo, Newtonsoft.Json.Serialization.JsonContract, System.Type)

Inner Exception 1:
InvalidCastException: Null object cannot be converted to a value type.

Environment:

Tr00d commented 6 months ago

Hi @MarcusKohnert,

Does the JSON example come from a real scenario? StartTime is indeed not nullable, and so does EndTime. I think we get a problem because start_time is explicitely set to null, while end_time isn't provided at all.

I think I need to track that one down internally. I'd like to know what is the normal behavior.

I'll keep you posted on that one.

MarcusKohnert commented 6 months ago

Hi @Tr00d,

yes that event was produced in a real scenario and it is reproducible. If an outbound call is started and the receiver of the call rejects the call this event is send.

Here is another sample produced just now:

{
    "headers": {},
    "uuid": "b772e8f9-47fb-4e82-a27d-8c496a00a790",
    "network": "26201",
    "duration": "0",
    "start_time": null,
    "rate": "0.00000000",
    "price": "0.00000000",
    "from": [redacted],
    "to": [redacted],
    "conversation_uuid": "CON-d7724493-3465-4ee2-91de-c34cd1c508bd",
    "status": "completed",
    "direction": "outbound",
    "timestamp": "2024-05-08T08:05:52.951Z"
}
Tr00d commented 6 months ago

Hi @MarcusKohnert,

This has been fixed in the latest version, v7.2.2.

Let me know if it works out for you.

Tr00d commented 5 months ago

Closing issue after two weeks. Don't hesitate to reach out if yoou face any problem.