Json.Net輸出合約實作:將資料物件中某些欄位動態隱藏,不進行序列化

Newtonsoft的Json.Net用到最後,難免會基於安全或頻寬等需求,要將某些資料物件(ORM)的某屬性隱藏起來,不在序列化階段將其序列化並輸出。這篇文章就是要討論這個情況下的實作問題。

隱藏屬性的靜態做法

其實要隱藏屬性,Json.Net有提供許多簡單的作法,例如冠上[JsonIgnore]Attrubute就是一個非常直觀的做法。

public class Customer
{
  [JsonIgnore]  //加上這個屬性就會隱藏了
  public int CustId {get; set;}
  public string FirstName {get; set;}
}

隱藏屬性的半動態做法

Json.Net還有另外提供一個半動態的做法稱為有條件的屬性序列化(Conditional Property Serialization),序列化階段利用反射取得方法名稱(過濾掉ShouldSerialize字串)後再去對應屬性,執行判斷是否要進行該屬性的序列化,非常屌。詳情請看:ShouldSerialize

public class Employee
{
  public string Name { get; set; }
  public Employee Manager { get; set; }

  //如果Manager不是自己物件本身,就顯示這個屬性
  public bool ShouldSerializeManager()
  { return (Manager != this); }
}

隱藏屬性的全動態做法

上面舉例的靜態與半動態的做法,在後端實務上仍然有力有未逮之處,因此,我們又得搬出DefaultContractResolver出來練兵了。

public class JsonHiddenProperties : Newtonsoft.Json.Serialization.DefaultContractResolver
{
  /// <summary>
  /// 要隱藏的屬性名稱(字串陣列)
  /// </summary>
  public string[] aryHidden { get; set; } = new string[] { };

  public JsonHiddenProperties() { }

  protected override System.Collections.Generic.IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(System.Type oType, Newtonsoft.Json.MemberSerialization oMS)
  {
    var oJP = base.CreateProperties(oType, oMS);
    //實作LINQ NOT IN
    return oJP.Where(x => !aryHidden.Contains(x.PropertyName)).ToList();
  }
}

程式碼的工作原理很簡單,大致上就是你給我黑名單,我在序列化時期如果有看到不再黑名單內的屬性就往外丟(序列化),當然沒往外丟的就胎死腹中了(隱藏)。

套用DefaultContractResolver合約

套用方式很簡單,請參考下列的程式碼,你懂得!

public static void Main()
{
  Employee oEmployee = new Employee();
  oEmployee.cNameFirst  = "John1";
  oEmployee.cNameMiddle = "John2";  //這個在序列化後會消失
  oEmployee.cNameLast   = "John3";
  
  Console.WriteLine(
    Newtonsoft.Json.JsonConvert.SerializeObject(
      oEmployee,
      Newtonsoft.Json.Formatting.None,
      new Newtonsoft.Json.JsonSerializerSettings { ContractResolver = new JsonHiddenProperties() { aryHidden = new[] { "cNameMiddle" } }}
    )
  );
}

public class Employee
{
  public string cNameFirst  { get; set; }
  public string cNameMiddle { get; set; }
  public string cNameLast   { get; set; }
}

相關參考

Newtonsoft Json.Net DefaultContractResolver ORM POCO Property Properties Hide Hidden Disable