Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.ArgumentOutOfRangeException while deserializing using Newtonsoft.Json

I am using Newtonsoft JSON to deserialize an object that contains interfaces. Newtonsoft was having trouble "figuring out" how to map the interfaces to their concrete types on deserialization, so I was following the directions in this answer to fix the issue.

I am doing the following to deserialize:

var converter = new JsonSerializer();
converter.Converters.Add(new DeviceCalibrationConverter());

// Obviously parameter.value and typeObj being the JSON and Type respectively
// I can see stepping through this that these are, in fact, the correct values
object deserialized = converter.Deserialize(new StringReader(parameter.Value), typeObj);

I'm using the DeviceCalibrationConverter object to try to map my interface to its concrete type:

public class DeviceCalibrationConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // I am trying to map the IDeviceCalibration interface to its concrete type (DeviceCalibration)
        return objectType.Equals(typeof(IDeviceCalibration));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, typeof(DeviceCalibration));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

I'm currently getting an "ArgumentOutOfRangeException." Full exception details are below:

System.ArgumentOutOfRangeException was unhandled
  HResult=-2146233086
  Message=Version's parameters must be greater than or equal to zero.
Parameter name: build
  Source=mscorlib
  ParamName=build
  StackTrace:
       at System.Version..ctor(Int32 major, Int32 minor, Int32 build, Int32 revision)
       at Void .ctor(Int32, Int32, Int32, Int32)(Object[] )
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
       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.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.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(TextReader reader, Type objectType)
       at FunctionalTesting.ExecuteXMLScript.Execute() in [folder]\ExecuteXMLScript.cs:line 141
       at FunctionalTesting.TestRunner.RunTests() in [folder]\TestRunner.cs:line 102
       at FunctionalTesting.Program.Main(String[] args) in [folder]\Program.cs:line 43
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

This occurs, by the way, on the line where I try to call Deserialize.

Edit: The entire JSON is pretty lengthy but it turns out that the offending line is as follows:

{"State":"needs-translation","OriginalString":"LP","StringID":[id],"StringValue":"LP"}}],
"MarketingFeatures":null,
 "CDIDriver" {"Name":"[Product Name]",
 "Version":{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}}

In particular, in "Version" deserializes to:

{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}

This deserializes to the System.Version class and this is invalid, thus producing the exception I listed above.

CDIDriver, by the way, creates the Version object as follows:

Version = new Version((int)major, (int)minor);

This is perfectly valid, and the document does, in fact, say that using this constructor as described will set the build and revision to -1 (as shown in the JSON). My question, then, is if this is a perfectly valid, document state of the object, why does it produce this exception when I try to deserialize it?

I am aware that trying to do something like new Version(1, 0, -1, -1) will produce an exception and that this is the documented behavior. (This seems like very odd behavior given that that would result in a valid object state, but that's just my opinion). Is there some way around having to do:

new Version(1, 0, 0, 0)

just for the sake of making the deserialization work?

like image 783
EJoshuaS - Stand with Ukraine Avatar asked Aug 15 '16 20:08

EJoshuaS - Stand with Ukraine


People also ask

Is Newtonsoft JSON still supported?

Yet Newtonsoft. Json was basically scrapped by Microsoft with the coming of . NET Core 3.0 in favor of its newer offering designed for better performance, System. Text.

How do I use Newtonsoft JSON?

Use the Newtonsoft. Json; To build and run the app, press F5 or select Debug > Start Debugging. Select the Click Me button to see the contents of the TextBlock object replaced with JSON text.

Does JsonConvert DeserializeObject throw exception?

Serialization or deserialization errors will typically result in a JsonSerializationException .

Why do we use Newtonsoft JSON?

The Newtonsoft. JSON namespace provides classes that are used to implement the core services of the framework. It provides methods for converting between . NET types and JSON types.


1 Answers

The Version has not been serialized in the right way.

If done correctly it should loke like this:

{
    ...
    "Version": "1.0"
}

This can be achieved by using the VersionConverter like so:

var json = JsonConvert.SerializeObject(new Version(1, 0), new VersionConverter());

Deserialization also has to use this converter:

var obj = JsonConvert.DeserializeObject<Version>(json, new VersionConverter());

Working example: https://dotnetfiddle.net/eAqwip

Note that you can also annotate the de/serialized class with a JsonConverterAttribute to achieve the same automatically:

public class DeviceCalibration
{
    ...

    [JsonConverter(typeof(VersionConverter))]
    public Version Version { get; set }
}

If you don't have access to the serializer code, I'm afraid you will have to fix the Json string "by hand" or write your own VersionConverter that can handle -1 values.

like image 77
Good Night Nerd Pride Avatar answered Sep 22 '22 06:09

Good Night Nerd Pride