JSON.NET:如何判断序列化对象的类型是否与请求的类型不同?

时间:2015-07-27 14:01:17

标签: c# .net json serialization

如果指示这样做,JSON.NET(Newtonsoft.Json)可以将序列化对象的类型存储在输出字符串中。通过将 TypeNameHandling 设置为枚举中的某些值,不同于 TypeNamehandling.None ,输出可能如下所示:

JsonConvert.SerializeObject(<object>,
    new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All })

要序列化的对象在哪里。

结果输出字符串将包含

{"$type":"<type_name>"...

另一方面,文档说明了设置

TypeNameAssemblyFormat = FormatterAssemblyStyle.Full

将在反序列化期间检查类型名称(&#34;获取或设置类型名称程序集的编写方式以及序列化程序已解决。&#34; - JSON的副本。 NET文档)。

尽管我明确设置了错误处理程序,但没有生成错误,因此处理程序保持静默。反序列化对象不为null,但序列化内容中没有相应名称(并且不存在从序列化值转换为其类型)的所有属性都为空。这可能是一个理想的行为,但我想要做的是序列化类型和请求反序列化的类型之间的类型不匹配的任何迹象。

我尊重这一点,我不想做的是解析序列化的内容,而不是这是一个大问题,而是因为它可能被认为是内部信息,与序列化过程相关。

现在我的问题是:如何通知序列化对象的类型与请求反序列化的对象类型不同?

PS:我用

JsonConvert.SerializeObject<T>(Object value, JsonSerializerSettings settings) 

JsonConvert.DeserializeObject<T>(string value, JsonSerializerSettings settings)

谢谢!

2 个答案:

答案 0 :(得分:1)

您可以检查生成的JSON

IDictionary<string, JToken> dictionary = JObject.Parse(json);
if (dictionary.ContainsKey("$type"))

答案 1 :(得分:1)

在解析类型名称时,默认情况下Json.NET使用DefaultSerializationBinder.BindToType(assemblyName, typeName),最终在大多数平台上调用Assembly.LoadWithPartialName()

#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
            // look, I don't like using obsolete methods as much as you do but this is the only way
            // Assembly.Load won't check the GAC for a partial name
#pragma warning disable 618,612
            assembly = Assembly.LoadWithPartialName(assemblyName);
#pragma warning restore 618,612
#elif NETFX_CORE || PORTABLE
            assembly = Assembly.Load(new AssemblyName(assemblyName));
#else
            assembly = Assembly.Load(assemblyName);
#endif

在Visual Studio中进行一些实验后,只要名称和PublicKeyToken值匹配,加载DLL时,此方法似乎将静默且成功地匹配具有不同版本号的程序集从磁盘。

我不确定为什么使用这个方法,但是你可以用一个子类替换默认绑定器,该子类检查预期和已解决的程序集版本是否完美匹配,如果没有,则抛出异常(或者做任何你想做的事情) ):

public class AssemblyVersionSerializationBinder : DefaultSerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        var type = base.BindToType(assemblyName, typeName);
        if (type != null)
        {
            var name = new AssemblyName(assemblyName);
            // If assemblyName has a version specified and it does not match the version of the loaded assembly, raise an error.
            if (name.Version != null && name.Version != type.Assembly.GetName().Version)
            {
                HandleAssemblyNameMismatch(type, assemblyName, typeName);
            }
        }
        return type;
    }

    private void HandleAssemblyNameMismatch(Type type, string assemblyName, string typeName)
    {
        string message = string.Format("Mismatch between expected assembly name \"{0}\" and loaded assembly name \"{1}\"", type.Assembly.FullName, assemblyName);
        Debug.WriteLine(message);
        throw new JsonSerializationException(message);
    }
}

然后使用它:

        var settings = new JsonSerializerSettings { 
            TypeNameHandling = TypeNameHandling.Objects, 
            TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, 
            Binder = new AssemblyVersionSerializationBinder() };