Thursday, May 14, 2020

How to ignore property conditionally during JSON serialization

Consider i have class Employer, i want serialize this class to json string and need ignore some properties conditionally. For ex: in my example, i want to include address1 and address2 only if it has valid values


  public class Employer
    {
 public int id { get; set; }

        public string name { get; set; }
       
 public string ssn { get; set; }

        public string address1 { get; set; }

        public string address2 { getset; }
   }



Declare some values


Employer employer = new Employer(){ … address1 = "some value", address2 = null };


Now serialize it for json string


var jsonstring = JsonConvert.SerializeObject(employer,
                       Newtonsoft.Json.Formatting.None,
                       new JsonSerializerSettings
                       {
                           
                       });

Here you will get all the properties.

Now lets see how to ignore the properties conditionally, you can choose either one of these options.

Option 1: Use ShouldSerialize property inside class itself like below. But you need add individual shouldSerialize property for each class property.

  public class Employer
    {
 public int id { get; set; }

        public string name { get; set; }
       
 public string ssn { get; set; }

        public string address1 { get; set; }

        public string address2 { get; set; }

        public bool ShouldSerializeaddress1()
        {
            // don't serialize if it is null or empty or add any your custom conditions
            return !string.IsNullOrEmpty(address1);
        }
        public bool ShouldSerializeaddress2()
        {
            // don't serialize if it is null or empty or add any your custom conditions
            return !string.IsNullOrEmpty(address2);
        }

   }


Option 2: Instead creating multiple ShouldSerialize property inside class, we can create ContractResolver and add it in Json serialization as below,

Create Resolver Class,

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Linq;
using System.Reflection;
...

  public class EmployerShouldSerializeContractResolver : DefaultContractResolver
    {
        public new static readonly EmployerShouldSerializeContractResolver Instance = new EmployerShouldSerializeContractResolver();

        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);

            if (property.DeclaringType == typeof(Employer))
            {
                property.ShouldSerialize =
                    instance =>
                    {
                        //ignore default values
                        return instance.GetType().GetProperty(member.Name).GetValue(instance, null) != property.DefaultValue;
                    };
            }

            return property;
        }

    }


Include it in JSON serialization,

var jsonstring = JsonConvert.SerializeObject(employer,
                       Newtonsoft.Json.Formatting.None,
                       new JsonSerializerSettings
                       {
                           ContractResolver = new EmployerShouldSerializeContractResolver()
                       });


Friday, April 24, 2020

Angular CLI - Custom Date validator

Angular supports of custom validators. Here i have created custom validator to validate date for template drive forms.

Directive: date-validator.directive.ts


import { AbstractControl, ValidatorFn, FormControl } from '@angular/forms';
import * as moment from 'moment';
import { NG_VALIDATORS, Validator } from '@angular/forms';
import { Directive } from '@angular/core';

// validation function
function validateDateFactory(): ValidatorFn {
  return (c: AbstractControl) => {

    let isValid = moment(c.value, 'M/D/YYYY', true).isValid();

    if (isValid) {
      return null;
    } else {
      return {
        validDate: {
          valid: false
        }
      };
    }
  }
}

@Directive({
  selector: '[validDate][ngModel]',
  providers: [
    { provide: NG_VALIDATORS, useExisting: ValidDateValidator, multi: true }
  ]
})
export class ValidDateValidator implements Validator {
  validator: ValidatorFn;

  constructor() {
    this.validator = validateDateFactory();
  }

  validate(c: FormControl) {
    return this.validator(c);
  }

}


Html:
<input type="text" [(ngModel)]="someDateModal" validDate />