Json.net将属性添加到包含特定类型的每个类

时间:2017-10-03 16:53:39

标签: .net json.net

我想为我的json为DateTime类型的每个属性添加一个属性。

我有一个自定义转换器,并在CreateProperties上有一个覆盖(见下文)。调试返回的属性列表时,会保留新值,但是当json到达浏览器时,它不包含新属性

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);

        foreach(var prop in base.CreateProperties(type, memberSerialization))
        {
            if(prop != null
                && (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?)))
            {
                properties.Add(new JsonProperty() {
                    PropertyName = String.Format("{0}$$type", prop.PropertyName),
                    PropertyType = typeof(String)
                });
            }
        }
        return properties;
    }

首先想到的是,之后新的Json属性被删除,因为它们无效。可能是因为它们没有价值,但是我看不到在这里设置值的方法。

任何想法都会受到欢迎

1 个答案:

答案 0 :(得分:1)

您正尝试通过custom contract resolver向您的序列化JSON添加合成只读属性。您的问题是您没有完全初始化JsonProperty所需的值。至少你必须初始化

此外,建议初始化:

以下操作,添加值为"DateTime"的固定字符串属性:

public class AddDateTypeFlagContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        for (int i = 0, n = properties.Count; i < n; i++)
        {
            var prop = properties[i];
            if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
            {
                var name = string.Format("{0}$$type", prop.PropertyName);
                var newProp = new JsonProperty
                {
                    DeclaringType = type,
                    PropertyName = name,
                    UnderlyingName = name,
                    PropertyType = typeof(string),
                    ValueProvider = new FixedValueProvider("DateTime"), // Replace with yout desired string value.
                    AttributeProvider = NoAttributeProvider.Instance,
                    Readable = true,
                    Writable = false,
                    // Ensure PreserveReferencesHandling and TypeNameHandling do not apply to the synthetic property.
                    ItemIsReference = false, 
                    TypeNameHandling = TypeNameHandling.None,
                };
                properties.Add(newProp);
            }
        }

        return properties;
    }
}

public class FixedValueProvider : IValueProvider
{
    readonly object value;

    public FixedValueProvider(object value)
    {
        this.value = value;
    }

    #region IValueProvider Members

    public object GetValue(object target) { return value; }

    public void SetValue(object target, object value)
    {
        throw new NotImplementedException("SetValue not implemented for fixed properties; set JsonProperty.Writable = false.");
    }

    #endregion
}

class NoAttributeProvider : IAttributeProvider
{
    static NoAttributeProvider() { instance = new NoAttributeProvider(); }

    static readonly NoAttributeProvider instance;

    public static NoAttributeProvider Instance { get { return instance; } }

    public IList<Attribute> GetAttributes(Type attributeType, bool inherit) { return new Attribute[0]; }

    public IList<Attribute> GetAttributes(bool inherit) { return new Attribute[0]; }
}

然后,给出以下示例类型:

public class Example
{
    public string NotADate { get; set; }
    public DateTime ADate { get; set; }
    public DateTime? AnotherDate { get; set; }
}

生成以下JSON:

{
  "NotADate": "a value",
  "ADate": "2017-04-23T14:25:43.511-04:00",
  "AnotherDate": "2017-04-23T14:25:43.511-04:00",
  "ADate$$type": "DateTime",
  "AnotherDate$$type": "DateTime"
}

还可以基于其他属性创建合成属性。例如,以下内容为模型中的每个Date属性添加了DateTime属性:

public class AddDateFromDateTimeContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        for (int i = 0, n = properties.Count; i < n; i++)
        {
            var prop = properties[i];
            if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
            {
                var name = string.Format("{0}$$date", prop.PropertyName);
                var newProp = new JsonProperty
                {
                    DeclaringType = type,
                    PropertyName = name,
                    UnderlyingName = name,
                    PropertyType = prop.PropertyType,
                    ValueProvider = new DateTimeToDateValueProvider(prop.ValueProvider),
                    AttributeProvider = NoAttributeProvider.Instance,
                    Readable = true,
                    Writable = false,
                    // Ensure PreserveReferencesHandling and TypeNameHandling do not apply to the synthetic property.
                    ItemIsReference = false,
                    TypeNameHandling = TypeNameHandling.None,
                };
                properties.Add(newProp);
            }
        }

        return properties;
    }
}

public class DateTimeToDateValueProvider : ValueProviderDecorator
{
    public DateTimeToDateValueProvider(IValueProvider baseProvider) : base(baseProvider) { }

    public override object GetValue(object target)
    {
        var baseValue = base.GetValue(target);
        if (baseValue is DateTime)
        {
            return ((DateTime)baseValue).Date;
        }
        return baseValue;
    }

    public override void SetValue(object target, object value)
    {
        throw new NotImplementedException();
    }
}

public abstract class ValueProviderDecorator : IValueProvider
{
    readonly IValueProvider baseProvider;

    public ValueProviderDecorator(IValueProvider baseProvider)
    {
        if (baseProvider == null)
            throw new ArgumentNullException();
        this.baseProvider = baseProvider;
    }

    public virtual object GetValue(object target) { return baseProvider.GetValue(target); }

    public virtual void SetValue(object target, object value) { baseProvider.SetValue(target, value); }
}

请注意,值提供程序是通过将原始属性的值提供程序包装在装饰器中来创建的,该装饰器将其值转换为所需的结果。另请注意,JsonProperty.PropertyType设置为要返回的预期类型。使用此合约解析程序,从Example类型生成以下JSON:

{
  "NotADate": "a value",
  "ADate": "2017-04-23T14:25:43.511-04:00",
  "AnotherDate": "2017-04-23T14:25:43.511-04:00",
  "ADate$$date": "2017-04-23T00:00:00-04:00",
  "AnotherDate$$date": "2017-04-23T00:00:00-04:00"
}

示例fiddle展示两个合同解析器。