使用newtonsoft.json库创建自定义JSON转换器,以获取其他数据,而无需覆盖CanRead和CanWrite



我当前正在处理WebAPI项目中使用的自定义JSON转换器。要求是 - 我有一个具有一些属性的DTO对象。API可以由多个客户消费。根据客户的不同,我的DTO实体中的几个可能还具有一些其他数据,除了DTO模型中已经存在的属性。我需要创建一个自定义的JSON转换器来序列化并进行序列化此数据。

//DTO
class AbcDTO
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public List<AdditionalProperty> AdditionalData { get; set; }
}
//AdditionalProperty class
class AdditionalProperty
{
    public string Name { get; set; }
    public object Value { get; set; }
}
//Request JSON Body
{
    "Prop1": "Val1",
    "Prop2": "Val2",
    "AdditionalProp3": "Val3",
    "AdditionalProp4": "Val4"
}
//After Deserialization the object should be as below
AbcDTO dto = {
    Prop1 = "Val1",
    Prop2 = "Val2",
    AdditionalData = [
    { Name = "AdditionalProp3", Value = "Val3" },
    { Name = "AdditionalProp4", Value = "Val4" }]
}
//After Serialization of the above dto object the JSON should convert back to the Request JSON Body format

我们不想使用newtonsoft.json提供的 JsonExtensionData属性,因为我们需要将属性保留为 Dictionary<string, JToken>-但我们不想将 JToken传递到下面的层。

创建一个自定义JSON转换器 -

class CustomJsonConverter : JsonConverter
{
    bool _canWrite = true;
    bool _canRead = true;
    public override bool CanConvert(Type objectType)
    {
        return typeof(IEntity).IsAssignableFrom(objectType);
    }
    public override bool CanWrite
    {
        get
        {
            return _canWrite;
        }
    }
    public override bool CanRead
    {
        get
        {
            return _canRead;
        }
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jObject = JObject.Load(reader);
        PropertyInfo[] availablePropertyNames = objectType.GetProperties();
        List<AdditionalProperties> additionalData = new List<AdditionalProperties>();
        IEntity obj;
            _canRead = false;
            obj = (IEntity)jObject.ToObject(objectType);
            _canRead = true;
        IEnumerable<JProperty> properties = jObject.Properties();
        foreach (JProperty prop in properties)
        {
            if (availablePropertyNames.Count(x => x.Name.Equals(prop.Name)) == 0)
            {
                AdditionalProperties addProp = new AdditionalProperties
                {
                    Name = prop.Name,
                    Value = prop.Value.ToObject<object>(),
                };
                additionalData.Add(addProp);
            }
        }
        obj.AdditionalData = additionalData;
        return obj;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        IEntity obj = (IEntity)value;
        List<AdditionalProperties> additionalData = obj.AdditionalData;
        JObject jObj;
        _canWrite = false;
        jObj = (JObject)JToken.FromObject(obj);
        _canWrite = true;
        jObj.Remove("AdditionalData");
        foreach (AdditionalProperties data in additionalData)
        {
            jObj.Add(data.Name, JToken.FromObject(data.Value));
        }
        jObj.WriteTo(writer);
    }
}

Webapi违规器每个实体创建1个JSON转换器。现在问题是_ canread,_ Canwrite不是线程安全。需要使用它们使用Newtonsoft提供的基本实现。如果我们不使用它们,则会再次调用内部定制转换器方法,从而导致无限递归。将它们与日志一起降低性能。有什么办法可以使用newtonsoft的基本实现来创建一个自定义转换器。JSON序列化/delelialization,而无需使用CanRead和CanWrite flag?

我也可以拥有参考类型的儿童属性 - 说人们包含地址。我想捕获父母和儿童实体的其他数据。其他数据将不包含参考类型的数据。

可以使用线程静态变量或ThreadLocal<T>成员禁用转换器,如JSON.NET所示,在使用JSONCONCONVERT或修改JSON的通用方法之前,请在返回给客户端。但是,我想提出一种更简单的方法来解决您的问题。

您写了,我们不想使用newtonsoft.json提供的jsonextensiondata属性,因为我们需要将属性保留为字典,我们不想将jtoken传递给以下层。没有必要对于扩展数据字典,具有JToken类型的值。类型object的值支持扩展数据字典,例如:

class AbcDTO
{
    public AbcDTO() { this.AdditionalData = new Dictionary<string, object>(); }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    [JsonExtensionData]
    public Dictionary<string, object> AdditionalData { get; private set; }
}

当扩展数据字典是Dictionary<string, object>类型时,JSON.NET将对JSON原始值进行对等效的.NET原始值 - stringboollong等 - 而不是JValue对象。只有在遇到一个值为JSON对象或数组的附加属性时,JToken才会添加到字典中,在这种情况下,您可以使用如何使用JSON.NET的答案将json.net从嵌套/递归词典和列表中进行验证?将JToken转换为常规.NET类型。(但是,您的问题指出,其他数据将不包含参考类型的数据,因此不需要。)

以这种方式使用 [JsonExtensionData]完全避免了对转换器的需求,同时又根据您的要求进行了典型化启动,因此似乎比问题所示的原始设计要简单得多。

样品.NET小提琴,证明了扩展属性可以被划分为AbcDTO,并断言它们都不是类型JToken

相关内容

  • 没有找到相关文章

最新更新