如何动态地向json对象添加属性?

时间:2016-12-25 12:04:20

标签: c# json json.net

我们在项目中使用Json.Net来序列化和反序列化json对象。

我们的实体有一些DateTime属性,我希望能够将它们转换为PersianCalender DateTime并在json对象中将它们作为字符串提供:

例如我们有这个实体:

public class PersonCertificate
{
      public DateTime CertificateDate{get;set;}
}

我想有一个像这样的json对象:

{
    "PersianCertificateDate":"1395/10/10"
}

所以我认为有一个名为" AsPersianDate"的属性会很棒。例如,我可以做这样的事情:

public class PersonCertificate
{
      [JsonIgnore]
      [AsPersianDate]
      public DateTime CertificateDate{get;set;}
}

我知道我可以使用自定义合约解析程序拦截json属性创建过程,但我不知道如何告诉Json.NetPersianCertificateDate反序列化为CertificateDate

1 个答案:

答案 0 :(得分:1)

好吧这比我想象的容易得多。实际上,ContractResolver负责获取和设置所有属性值,所以这就是我所做的:

public class EntityContractResolver:DefaultContractResolver
    {
        private class PersianDateValueProvider:IValueProvider
        {
            private readonly PropertyInfo _propertyInfo;

            public PersianDateValueProvider(PropertyInfo propertyInfo)
            {
                _propertyInfo = propertyInfo;
            }


            public void SetValue(object target, object value)
            {
                try
                {
                    var date = value as string;
                    if(value==null && _propertyInfo.PropertyType==typeof(DateTime))
                        throw new InvalidDataException();
                    _propertyInfo.SetValue(target,date.ToGregorianDate());
                }
                catch (InvalidDataException)
                {
                    throw new ValidationException(new[]
                    {
                        new ValidationError
                        {
                            ErrorMessage = "Date is not valid",
                            FieldName = _propertyInfo.Name,
                            TypeName = _propertyInfo.DeclaringType.FullName
                        }
                    });
                }
            }

            public object GetValue(object target)
            {
                if(_propertyInfo.PropertyType.IsNullable() && _propertyInfo.GetValue(target)==null) return null;
                try
                {
                    return ((DateTime) _propertyInfo.GetValue(target)).ToPersian();
                }
                catch
                {
                    return string.Empty;
                }

            }
        }


        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var list= base.CreateProperties(type, memberSerialization).ToList();
            list.AddRange(type.GetProperties()
                .Where(pInfo => IsAttributeDefined(pInfo,typeof(AsPersianDateAttribute))&& (pInfo.PropertyType == typeof (DateTime) || pInfo.PropertyType == typeof (DateTime?)))
                .Select(CreatePersianDateTimeProperty));
            return list;
        }

        private JsonProperty CreatePersianDateTimeProperty(PropertyInfo propertyInfo)
        {
            return new JsonProperty
            {
                PropertyName = "Persian"+propertyInfo.Name ,
                PropertyType = typeof (string),
                ValueProvider = new PersianDateValueProvider(propertyInfo),
                Readable = true,
                Writable = true
            };
        }

        private bool IsAttributeDefined(PropertyInfo propertyInfo,Type attribute)
        {
            var metaDataAttribute = propertyInfo.DeclaringType.GetCustomAttribute<MetadataTypeAttribute>(true);
            var metaDataProperty = metaDataAttribute?.MetadataClassType?.GetProperty(propertyInfo.Name);
            var metaDataHasAttribute = metaDataProperty != null && Attribute.IsDefined(metaDataProperty, attribute);

            return metaDataHasAttribute || Attribute.IsDefined(propertyInfo, attribute);
        }
    }