1

We are using Json.Net in our project to serialize and deserialize json objects.

Our entities have some DateTime properties and I would like to be able to convert them into PersianCalender DateTime and to provide them as string in my json object:

for example we have this entity :

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

I would like to have a json object like this :

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

So I thought that would be great to have an attribute named "AsPersianDate" for example so that I could do something like this:

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

I know that I can have a custom contract resolver to intercept json property creation process but I don't know how should I tell Json.Net to deserialize PersianCertificateDate into CertificateDate ?

3
  • You could add a 2nd property, and it would be left empty when you do json-to-object, because the json doesn't have that property. But then you can calculate it according to the Date, and then your object-to-json will have that extra piece of data. Commented Dec 25, 2016 at 12:13
  • that is what I am doing right now the problem is that I have to add these extra properties for all of my entities but I only need them when I want to serialize and deserialize my objects. Commented Dec 25, 2016 at 12:18
  • So make a derived class that only adds those properties, and is only used for serialize and deserialize, and your "real" classes remain clean. The derived classes can even be private within a class, so they don't even add junk to the intellisense throughout your project. Commented Dec 25, 2016 at 13:09

1 Answer 1

1

OK it was far more easier than I thought.Actually ContractResolver is responsible for getting and setting all property values so here's what I have done:

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);
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.