2017-08-28 46 views
1

因此,我有两个类,如下面的类。它们都在相同的命名空间和相同的共享项目中。Newtonsoft.json序列化和反序列化base/inheirited类来自共享项目

public class Person{ 
    public string Name{get;set;} 
} 

public class EmployedPerson : Person{ 
    public string JobTitle{get;set;} 
} 

当我serilize这些物品放入的RabbitMQ我序列化的基类,像这样:反序列化时

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, 
    TypeNameHandling = TypeNameHandling.Objects 
}; 
JsonConvert.SerializeObject(input, settings) 

但是我遇到的问题。我希望能够做到像下面显示的那样将反序列化作为基类,然后检查它是否是不合意的类型。

类型检查:

Person person = Deserialize<Person>(e.Body, Encoding.Unicode); 
    if (person is EmployedPerson) 
    { 
    logger.LogInformation("This person has a job!"); 
    } 

反序列化设置:

JsonSerializerSettings settings = new JsonSerializerSettings 
    { 
     TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, 
     TypeNameHandling = TypeNameHandling.Auto 
    }; 

反序列化逻辑:

private static T Deserialize<T>(byte[] data, Encoding encoding) where T : class 
    { 
     try 
     { 
      using (MemoryStream stream = new MemoryStream(data)) 
      using (StreamReader reader = new StreamReader(stream, encoding)) 
       return JsonSerializer.Create(settings).Deserialize(reader, typeof(T)) as T; 
     } 
     catch (Exception e) 
     { 
      Type typeParameter = typeof(T); 
      logger.LogError(LogEvent.SERIALIZATION_ERROR, e, "Deserializing type {@TypeName} failed", typeParameter.Name); 
      logger.LogInformation(Encoding.UTF8.GetString(data)); 
      return default(T); 
     } 
    } 

结果: 上面的代码失败,因为$类型属性包含大会名称在rabbitmq的每一端,程序集名称是不同的导致类在共享项目中。

实例错误:

Newtonsoft.Json.JsonSerializationException: Error resolving type specified in JSON 'Shared.Objects.EmployedPerson, Person.Dispatcher'. Path '$type', line 1, position 75. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Person.Dispatcher, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. 
+0

我认为这有可能会是一个回答您的问题: https://stackoverflow.com/questions/12381636/why-is-json-net-is-not-working-with-inheritance-while - 反序列化 –

+0

你可以1)写一个[自定义'SerializationBinder'](https://www.newtonsoft.com/json/help/html/SerializeSerializationBinder.htm)。编写你自己的活页夹清理反序列化的类型也是一个好主意,出于安全原因,这里解释[https://stackoverflow.com/q/39565954/3744182]。 2)发出你自己的自定义类型属性,并用一个自定义的'JsonConverter'解析它,如[Json.Net带多形子对象类型的序列化](https://stackoverflow.com/q/29528648/3744182) 。 – dbc

+0

纵观SerializationBinder。 – Theyouthis

回答

2

谢谢@dbc,您的建议编写自定义SerializationBinder是,据我所知,我的问题的最佳解决方案。

我用KnownTypesBinder作为实施:https://www.newtonsoft.com/json/help/html/SerializeSerializationBinder.htm

KnownTypesBinder:

public class KnownTypesBinder : ISerializationBinder 
    { 
     public IList<Type> KnownTypes { get; set; } 

     public Type BindToType(string assemblyName, string typeName) 
     { 
      return KnownTypes.SingleOrDefault(t => t.Name == typeName); 
     } 

     public void BindToName(Type serializedType, out string assemblyName, out string typeName) 
     { 
      assemblyName = null; 
      typeName = serializedType.Name; 
     } 
    } 

JsonSerializerSettings设置为KnownTypesBinder的一个实例SerializationBinder是在序列化和反序列化端点使用。我可能只需要它用于反序列化的结束,但为了一致性而将它放在一起。

settings = new JsonSerializerSettings 
{ 
    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, 
    TypeNameHandling = TypeNameHandling.Objects, 
    SerializationBinder = new KnownTypesBinder() 
}; 

创建设置对象后,我将它传递到JsonConvert序列化函数。

JsonConvert.DeserializeObject<T>(Encoding.Unicode.GetString(input), settings) 

还要注意的是,在KnownTypesBinder KnownTypes必须与所有你会被反序列化非基本类型的预先填充。

编辑: 我目前不接受我自己的答案,因为我不知道如何处理复杂类型的列表。例如,如果一个Person有一个List和一个List,那么当typeName是“List`1”时它返回的是什么类型,它可以是一个。

编辑 以下版本的KnownTypesBinder解决了与对象列表有关的问题。

public class KnownTypesBinder: ISerializationBinder 
{ 
    public IList<Type> KnownTypes { get; set; } 

    public Type BindToType(string assemblyName, string typeName) 
    { 
     return KnownTypes.SingleOrDefault(t => t.UnderlyingSystemType.ToString() == typeName); 
    } 

    public void BindToName(Type serializedType, out string assemblyName, out string typeName) 
    { 
     assemblyName = null; 
     typeName = serializedType.UnderlyingSystemType.ToString(); 
    } 
}