Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Newtonsoft json.net deserialization NullReferenceException

I have a simple JSON generated with WCF Rest client, but when I try to deserialize a response I get an error NullReferenceException in JSON.Net. I have following JSON:

{"Code":-2146232800,"ExceptionType":"IOException","Message":"Msg","Stacktrace":"Some"}

And following class:

[DataContract]
public class FileUploadError
{
    public FileUploadError(Exception exception)
    {
        Code = exception.HResult;
        ExceptionType = exception.GetType().Name;
        Message = GetMessage(exception);
        Stacktrace = exception.StackTrace;
        if (exception.Data.Count > 0)
        {
            Data = string.Join(Environment.NewLine, exception.Data.Cast<DictionaryEntry>().Select(x => x.Key + "=" + x.Value));
        }
    }

    private string GetMessage(Exception exception)
    {
        if (exception.InnerException == null)
        {
            return exception.Message;
        }
        const string delimiter = "->";
        var sb = new StringBuilder(1024);
        for (var ex = exception; ex != null; ex = ex.InnerException)
        {
            sb.Append(ex.Message).Append(delimiter);
        }
        sb.Length -= delimiter.Length;
        return sb.ToString();
    }

    [DataMember(IsRequired = true)]
    [JsonProperty("Code", NullValueHandling = NullValueHandling.Ignore)]
    public int Code { get; set; }
    [DataMember(IsRequired = true)]
    [JsonProperty("ExceptionType", NullValueHandling = NullValueHandling.Ignore)]
    public string ExceptionType { get; set; }
    [DataMember(EmitDefaultValue = false)]
    [JsonProperty("Message", NullValueHandling = NullValueHandling.Ignore)]
    public string Message { get; set; }
    [DataMember(EmitDefaultValue = false)]
    [JsonProperty("Stacktrace", NullValueHandling = NullValueHandling.Ignore)]
    public string Stacktrace { get; set; }
    [DataMember(EmitDefaultValue = false)]
    [JsonProperty("Data", NullValueHandling = NullValueHandling.Ignore)]
    public string Data { get; set; }
}

Then I deserialize it:

const string text = "{\"Code\":-2146232800,\"ExceptionType\":\"IOException\",\"Message\":\"Msg\",\"Stacktrace\":\"Some\"}";
var obj = JsonConvert.DeserializeObject<FileUploadError>(text);

And get subj error. Reproduced in new console application, which I can provide if required. JSON is very simple, why I am getting this error?

Sample: https://dotnetfiddle.net/76FJd0

Stacktrace:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at FileUploadError..ctor(Exception exception) in d:\Windows\Temp\nclgvim3.0.cs:line 28
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, 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.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Program.Main(String[] args)
like image 844
Alex Zhukovskiy Avatar asked May 14 '16 17:05

Alex Zhukovskiy


People also ask

What is the result of deserializing the JSON?

The result of deserializing the JSON is three successfully deserialized dates and three error messages: one for the badly formatted string ("I am not a date and will error!"), one for the nested JSON array, and one for the null value since the list doesn't allow nullable DateTimes.

How do I serialize a JSON file?

Serializing and Deserializing JSON. The quickest method of converting between JSON text and a .NET object is using the JsonSerializer . The JsonSerializer converts .NET objects into their JSON equivalent and back again by mapping the .NET object property names to the JSON property names and copies the values for you.

Can I deserialize a JSON array of dates?

The result of deserializing the JSON is three successfully deserialized dates and three error messages: one for the badly formatted string ("I am not a date and will error!"), one for the nested JSON array, and one for the null value since the list doesn't allow nullable DateTimes.

What are the exceptions thrown when converting a JSON object?

JsonConvert.DeserializeObject can throw several unexpected exceptions (JsonReaderException is the one that is usually expected). These are: ArgumentException JsonSerializationException JsonWriterException NullReferenceException Documenta...


2 Answers

You need to add a public parameterless constructor to your FileUploadError class:

public class FileUploadError
{
    public FileUploadError()
    {
    }

Or, you could make it private and use [JsonConstructor]:

public class FileUploadError
{
    [JsonConstructor]
    private FileUploadError()
    {
    }

Or, leave it private and deserialize with ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor:

var settings = new JsonSerializerSettings
{
    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};
var obj = JsonConvert.DeserializeObject<FileUploadError>(text, settings);

with:

public class FileUploadError
{
    private FileUploadError()
    {
    }
like image 92
dbc Avatar answered Sep 30 '22 09:09

dbc


For those tumbling upon this later and since OP's specific case has been solved.

Here is what to do to get a clearer error message when it happens.

Source: https://www.newtonsoft.com/json/help/html/SerializationErrorHandling.htm

var errors = new List<string>();

List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(
    yourJsonHere,
    new JsonSerializerSettings
    {
        Error = delegate(object sender, ErrorEventArgs args)
        {
            errors.Add(args.ErrorContext.Error.Message);
            args.ErrorContext.Handled = true;
        }
    });

And errors will contain a list of the errors that occured! Works both for serialization and deserialization!

Doing so you do lose the context though! So alternatively you can set it to Handled = false.

like image 25
jeromej Avatar answered Sep 30 '22 11:09

jeromej