我们在项目中使用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.Net
将PersianCertificateDate
置于CertificateDate
中?
好吧,它比我想象的要容易得多。实际上,违规者负责获取和设置所有属性值,所以这就是我所做的:
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);
}
}