Custom $type value for serialized objects

后端 未结 1 1848
离开以前
离开以前 2020-12-19 13:07

We\'re using Web API with Json.Net using TypeNameHandling = TypeNameHandling.Objects in our serializer settings. This works fine, but we use the type informati

1条回答
  •  盖世英雄少女心
    2020-12-19 13:20

    Rather than adding a synthetic $type property, you should create a custom ISerializationBinder and override ISerializationBinder.BindToName. This method is called during serialization to specify the type information to emit when TypeNameHandling is enabled.

    For instance, the following strips the assembly information as well as the PROJECTNAME.Api. portion of the namespace:

    public class MySerializationBinder : ISerializationBinder
    {
        const string namespaceToRemove = "PROJECTNAME.Api.";
    
        readonly ISerializationBinder binder;
    
        public MySerializationBinder() : this(new Newtonsoft.Json.Serialization.DefaultSerializationBinder()) { }
    
        public MySerializationBinder(ISerializationBinder binder)
        {
            if (binder == null)
                throw new ArgumentNullException();
            this.binder = binder;
        }
    
        #region ISerializationBinder Members
    
        public void BindToName(Type serializedType, out string assemblyName, out string typeName)
        {
            binder.BindToName(serializedType, out assemblyName, out typeName);
            if (typeName != null && typeName.StartsWith(namespaceToRemove))
                typeName = typeName.Substring(namespaceToRemove.Length);
    
            assemblyName = null;
        }
    
        public Type BindToType(string assemblyName, string typeName)
        {
            throw new NotImplementedException();
        }
    
        #endregion
    }
    

    Then you can serialize your DtoName object with it as follows:

    var settings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        SerializationBinder = new MySerializationBinder(),
        TypeNameHandling = TypeNameHandling.Objects,
    };
    var json = JsonConvert.SerializeObject(dto, Formatting.Indented, settings);
    

    Notes:

    • Newtonsoft introduced ISerializationBinder in release 10.0.1 as a replacement to System.Runtime.Serialization.SerializationBinder, apparently because that type is missing in some versions of .Net core. If you are using a version of Json.NET that precedes 10.0.1 you will need to create a custom version of that instead.

      Note also that SerializationBinder.BindToName() was introduced in .Net 4.0, so if you are using an old version of Json.NET and an old version of .Net itself then this solution will not work.

    • As you are not doing deserialization in c# I simply threw an exception from BindToType(). But if someone were to implement BindToType(), they should take heed of the caution from TypeNameHandling caution in Newtonsoft Json and be sure to sanitize the incoming types to prevent construction of harmful types.

    0 讨论(0)
提交回复
热议问题