Home > Blockchain >  Deserialization contracts for properties
Deserialization contracts for properties

Time:02-15

I need to deserialize jsons to a type that contains a property of interface type - IExceptionModel. I prescribe maps for interfaces to classes like this:

public static class JsonSerialization
{
    public static T FromJson<T>(this string obj) => JsonConvert.DeserializeObject<T>(obj, Settings);
    
    public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new ContractResolver()
    };

    private class ContractResolver : DefaultContractResolver
    {
        protected override JsonContract CreateContract(Type objectType)
        {
            var result = base.CreateContract(objectType);
            if (objectType == typeof(IExceptionModel))
            {
                    result.CreatedType = typeof(Status);
                    result.DefaultCreator = () => result.CreatedType.GetConstructor(new Type[0]).Invoke(null);
            }
                
            return result;
        }
    }
}

Here are my interface and class types:

public interface IExceptionModel : IModelBase
{
    public string Message { get; set; }
    public byte Index { get; set; }

}
public class ExceptionModel : IExceptionModel
{
    public string Message { get ; set ; }
    public byte Index { get; set; }
}

Here is the class to deserialize to:

public class Status
{
    public IExceptionModel Error { get; set; }
}

When I take a proper input string like:

{
    "Error" : {
          "Message": "Error",
          "Index": 404
     }
}

and feed it to FromJson<Status> method, described above, I get Error property set to null, although I believe I have resolved the contract for the interface. What else do I need to do in order to make it work?

CodePudding user response:

I made some corrections and this worked for me:

result.CreatedType = typeof(Status); --> result.CreatedType = typeof(ExceptionModel);

public byte Index { get; set; } --> public int Index { get; set; }

I uploaded this online example: https://dotnetfiddle.net/ETSJee

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;


public interface IModelBase {}
    
public interface IExceptionModel : IModelBase
    {
        public string Message { get; set; }
        public int Index { get; set; }

    }
    public class ExceptionModel : IExceptionModel
    {
        public string Message { get ; set ; }
        public int Index { get; set; }
    }

    public class Status
    {
        public IExceptionModel Error { get; set; }
    }

public static class JsonSerialization
{
    public static T FromJson<T>(this string obj) 
    { 
        return JsonConvert.DeserializeObject<T>(obj, Settings);
    }

    public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new ContractResolver()
    };

    private class ContractResolver : DefaultContractResolver
    {
        protected override JsonContract CreateContract(Type objectType)
        {
            var result = base.CreateContract(objectType);
            if (objectType == typeof(IExceptionModel))
            {
                result.CreatedType = typeof(ExceptionModel);
                result.DefaultCreator = () => result.CreatedType.GetConstructor(new Type[0]).Invoke(null);
            }

            return result;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var txt = @"
        {
            'Error' : {
                'Message': 'Error',
                'Index': 404
            }
        }
        ";
        var obj = JsonSerialization.FromJson<Status>(txt);
        Console.WriteLine(obj.Error.Index);
        Console.WriteLine(obj.Error.Message);
    }
}


CodePudding user response:

this works for me without any contract resolvers

var status = JsonConvert.DeserializeObject<Status>(txt);

public class Status
{
    public IExceptionModel Error { get; set; }
    
   [JsonConstructor]
    public Status (ExceptionModel error) {
        Error=error;
    }
    public Status() {}
}
  • Related