I have JWT object with a certain payload claim. The claim has value a container of a list of permissions. Serialization is working fine but deserialization is not working. That container is unwrapped but not in correct type, it stays Newtonsoft.Json.Linq.JObject. I use .NET Core 2.0
namespace JsonConvertXUnitTestProject
{
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
public class Permission
{
public string Name { get; set; }
}
public class Container
{
public List<Permission> Permissions { get; set; }
}
public class Jwt : IEquatable<Jwt>
{
public Jwt()
{
Header = new Dictionary<string, object>();
Payload = new Dictionary<string, object>();
}
public Dictionary<string, object> Header { get; set; }
public Dictionary<string, object> Payload { get; set; }
public string Serialize()
{
Dictionary<string, object> dict = new Dictionary<string, object>
{
["header"] = JsonConvert.SerializeObject(Header),
["payload"] = JsonConvert.SerializeObject(Payload)
};
return JsonConvert.SerializeObject(dict);
}
public void Deserialize(string deserialized)
{
Dictionary<string, object> dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(deserialized);
Header = JsonConvert.DeserializeObject<Dictionary<string, object>>(dict["header"].ToString());
Payload = JsonConvert.DeserializeObject<Dictionary<string, object>>(dict["payload"].ToString());
}
public override bool Equals(object obj)
{
return Equals(obj as Jwt);
}
public static bool DictEquals(Dictionary<string, object> dict1, Dictionary<string, object> dict2)
{
if (dict1 == null && dict2 == null)
{
return true;
}
else if (dict1 != null && dict2 != null)
{
if (dict1 == dict2) // Reference comparison (if both points to same object)
{
return true;
}
else if (dict1.Count == dict2.Count)
{
return dict1.Except(dict2).Count() == 0;
}
}
return false;
}
public bool Equals(Jwt other)
{
return other != null &&
DictEquals(Header, other.Header) &&
DictEquals(Payload, other.Payload);
}
public override int GetHashCode()
{
var hashCode = 1268427973;
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<string, object>>.Default.GetHashCode(Header);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<string, object>>.Default.GetHashCode(Payload);
return hashCode;
}
public static bool operator ==(Jwt jwt1, Jwt jwt2)
{
return EqualityComparer<Jwt>.Default.Equals(jwt1, jwt2);
}
public static bool operator !=(Jwt jwt1, Jwt jwt2)
{
return !(jwt1 == jwt2);
}
}
public class ObjectJsonConvertUnitTest
{
[Fact]
public void TestObject()
{
Container cont = new Container
{
Permissions = new List<Permission>
{
new Permission() { Name = "open" },
new Permission() { Name = "close" }
}
};
Jwt t1 = new Jwt();
t1.Header["alg"] = "None";
t1.Header["kid"] = "1";
t1.Payload["sub"] = "Object";
t1.Payload["perm"] = cont;
Jwt t2 = new Jwt();
string serialized = t1.Serialize();
t2.Deserialize(serialized);
Assert.Equal(t1, t2);
}
[Fact]
public void TestObjectStrait()
{
Container cont = new Container
{
Permissions = new List<Permission>
{
new Permission() { Name = "open" },
new Permission() { Name = "close" }
}
};
Jwt t1 = new Jwt();
t1.Header["alg"] = "None";
t1.Header["kid"] = "1";
t1.Payload["sub"] = "Object";
t1.Payload["perm"] = cont;
Jwt t2 = new Jwt();
string serialized = JsonConvert.SerializeObject(t1);
t2 = JsonConvert.DeserializeObject<Jwt>(serialized);
Assert.Equal(t1, t2);
}
}
}
csproj package reference item group is here:
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
{"Header":{"alg":"None","kid":"1"},"Payload":{"sub":"Object","perm":{"Permissions":[{"Name":"open"},{"Name":"close"}]}}}
{
"Header": {
"alg": "None",
"kid": "1"
},
"Payload": {
"sub": "Object",
"perm": {
"Permissions": [{
"Name": "open"
},{
"Name": "close"
}
]
}
}
}
Expected behavior would be equality of objects input and output. The output get from input after application of serialization and deserialization consequently.
Output object is different from input. Container with permissions object is not fully deserialized, it is returned in a JObject instance.
Jwt t1 = new Jwt();
...
string serialized = JsonConvert.SerializeObject(t1);
t2 = JsonConvert.DeserializeObject<Jwt>(serialized);
Assert.Equal(t1, t2);
I have the very same behavior with .NET Framework 4.6.1 too.
Json.NET doesn't know what the serialized type is. All it has is JSON, so it defaults to JValue
Most helpful comment
Json.NET doesn't know what the serialized type is. All it has is JSON, so it defaults to JValue