如何从 Json 序列化中排除属性

Posted

技术标签:

【中文标题】如何从 Json 序列化中排除属性【英文标题】:How to exclude property from Json Serialization 【发布时间】:2012-04-27 12:26:53 【问题描述】:

我有一个我序列化的 DTO 类

Json.Serialize(MyClass)

如何排除它的 public 属性?

(它必须是公开的,因为我在其他地方的代码中使用它)

【问题讨论】:

你使用哪个序列化框架? IgnoreDataMember ScriptIgnore JsonIgnore 取决于您使用的序列化程序 另外值得注意的是[NonSerialized]属性,该属性只适用于字段(不是属性),其他方面与JsonIgnore作用相同。 Trynko 的评论很有用....如果在某个字段上使用 IgnoreDataMember 不会出错,但不会应用。 注意你的命名空间。 [JsonIgnore] 属性存在于 Newtonsoft.Json 和 System.Text.Json.Serialization 命名空间中。在模型上使用 Newtonsoft.Json.JsonIgnore 很容易,然后使用 System.Text.Json.Serialization.JsonSerializer.Serialize 来序列化您的模型(反之亦然)。然后 JsonIgnore 属性被忽略。 :) 【参考方案1】:

如果您使用 Json.Net,属性 [JsonIgnore] 在序列化或反序列化时将简单地忽略字段/属性。

public class Car

  // included in JSON
  public string Model  get; set; 
  public DateTime Year  get; set; 
  public List<string> Features  get; set; 

  // ignored
  [JsonIgnore]
  public DateTime LastModified  get; set; 

或者您可以使用 DataContract 和 DataMember 属性来选择性地序列化/反序列化属性/字段。

[DataContract]
public class Computer

  // included in JSON
  [DataMember]
  public string Name  get; set; 
  [DataMember]
  public decimal SalePrice  get; set; 

  // ignored
  public string Manufacture  get; set; 
  public int StockCount  get; set; 
  public decimal WholeSalePrice  get; set; 
  public DateTime NextShipmentDate  get; set; 

更多详情请参考http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size

【讨论】:

如果我是 OP,我会更喜欢这个答案而不是选择的 [ScriptIgnore] 解决方案。主要是由于 Json 解决方案的一致性,因此是 Json 问题。当您使用的库提供解决方案时,为什么要涉及 System.Web.Extensions?恕我直言,最好的绝对是 [IgnoreDataMember] 属性,因为如果您希望换出 Json,System.Runtime.Serialization 应该与每个序列化程序兼容。 NewtonSoft 完全帮助了我。它使我的 json 看起来很干净,而我的模型中没有包含任何杂乱无章的属性,这些属性仅用于后端。 @JC Raja 只有当该属性为空时,我才能在脱盐期间忽略该属性 [NewtonSoft.Json] 我只想忽略序列化。那么有什么解决方案吗? @user123456 如果值为空,为什么在反序列化时要忽略?为什么不只为属性设置一个空值,或者创建一个优雅地处理空值的属性?【参考方案2】:

如果您在 .NET 框架中使用 System.Web.Script.Serialization,您可以在不应序列化的成员上放置 ScriptIgnore 属性。请参阅取自here 的示例:

考虑以下(简化的)案例:

public class User 
    public int Id  get; set; 
    public string Name  get; set; 
    [ScriptIgnore]
    public bool IsComplete
    
        get  return Id > 0 && !string.IsNullOrEmpty(Name); 
     
 

在这种情况下,只有 Id 和 Name 属性将被序列化,因此生成的 JSON 对象将如下所示:

 Id: 3, Name: 'Test User' 

PS。不要忘记添加对“System.Web.Extensions”的引用以使其正常工作

【讨论】:

我在System.Web.Script.Serialization 命名空间中找到了ScriptIgnore 我发现 System.Web.Controller.Json()(即在 MVC 中返回 JsonResult)仅适用于 [ScriptIgnore],而不适用于 [JsonIgnore]。所以将这个用于 JsonResult 类型。是的,正确的参考是 System.Web.Script.Serialization。【参考方案3】:

对不起,我决定写另一个答案,因为其他答案都不够可复制粘贴。

如果您不想使用某些属性来装饰属性,或者如果您无权访问该类,或者如果您想决定在运行时序列化什么等等等等。这就是您在 Newtonsoft 中的做法。 json

//short helper class to ignore some properties from serialization
public class IgnorePropertiesResolver : DefaultContractResolver

    private readonly HashSet<string> ignoreProps;
    public IgnorePropertiesResolver(IEnumerable<string> propNamesToIgnore)
    
        this.ignoreProps = new HashSet<string>(propNamesToIgnore);
    

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (this.ignoreProps.Contains(property.PropertyName))
        
            property.ShouldSerialize = _ => false;
        
        return property;
    

用法

JsonConvert.SerializeObject(YourObject, new JsonSerializerSettings()
         ContractResolver = new IgnorePropertiesResolver(new[]  "Prop1", "Prop2" ) );

注意:如果您决定使用此答案,请确保缓存 ContractResolver 对象,否则性能可能会受到影响。

我已经在这里发布了代码,以防有人想添加任何东西

https://github.com/jitbit/JsonIgnoreProps

【讨论】:

像魅力一样工作。请注意,如果您需要与另一个解析器组合(例如 CamelCasePropertyNamesContractResolver,只需使用您的 IgnorePropertiesResolver(考虑到组合,可能会重命名为更准确的名称)并从 CamelCasePropertyNamesContractResolver 继承,而不是直接从 DefaultContractResolver 继承。 我为自己做了一个小改动...而不是构造函数采用 IEnumerable,我的采用 IEnumerable...这样您就不能传入拼写错误的属性名称。调用者需要使用 Type.GetProperty 从字符串中获取 PropertyInfo 绝妙的答案!你也可以使用public IgnorePropertiesResolver(params string[] propNamesToIgnore)作为你的构造函数,这样实现者就可以说new IgnorePropertiesResolver("Prop1", "Prop2") 我只是在尝试这个;我认为您最后有一个不需要的分号 3 个字符? 如果您无法硬编码是否排除某个属性,这是一个很好的答案。【参考方案4】:

你可以使用[ScriptIgnore]:

public class User

    public int Id  get; set; 
    public string Name  get; set; 
    [ScriptIgnore]
    public bool IsComplete
    
        get  return Id > 0 && !string.IsNullOrEmpty(Name); 
    

在这种情况下,ID 和名称只会被序列化

【讨论】:

您答案中的 URL 已损坏。如果您的控制器使用基本 MVC 控制器 return Json(...,那么 [ScriptIgnore] 应该在属性上使用什么? 我知道这是一个旧评论,但是是的,在 MVC 控制器中使用 [ScriptIgnore]。但请注意,如果您使用的是 SignalR,那么您也应该使用 [JsonIgnore]【参考方案5】:

如果您不像我那样热衷于使用属性来装饰代码,尤其是当您无法在编译时知道这里会发生什么时,这就是我的解决方案。

使用 javascript 序列化器

    public static class JsonSerializerExtensions
    
        public static string ToJsonString(this object target,bool ignoreNulls = true)
        
            var javaScriptSerializer = new JavaScriptSerializer();
            if(ignoreNulls)
            
                javaScriptSerializer.RegisterConverters(new[]  new PropertyExclusionConverter(target.GetType(), true) );
            
            return javaScriptSerializer.Serialize(target);
        

        public static string ToJsonString(this object target, Dictionary<Type, List<string>> ignore, bool ignoreNulls = true)
        
            var javaScriptSerializer = new JavaScriptSerializer();
            foreach (var key in ignore.Keys)
            
                javaScriptSerializer.RegisterConverters(new[]  new PropertyExclusionConverter(key, ignore[key], ignoreNulls) );
            
            return javaScriptSerializer.Serialize(target);
        
    


public class PropertyExclusionConverter : JavaScriptConverter
    
        private readonly List<string> propertiesToIgnore;
        private readonly Type type;
        private readonly bool ignoreNulls;

        public PropertyExclusionConverter(Type type, List<string> propertiesToIgnore, bool ignoreNulls)
        
            this.ignoreNulls = ignoreNulls;
            this.type = type;
            this.propertiesToIgnore = propertiesToIgnore ?? new List<string>();
        

        public PropertyExclusionConverter(Type type, bool ignoreNulls)
            : this(type, null, ignoreNulls)

        public override IEnumerable<Type> SupportedTypes
        
            get  return new ReadOnlyCollection<Type>(new List<Type>(new[]  this.type )); 
        

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        
            var result = new Dictionary<string, object>();
            if (obj == null)
            
                return result;
            
            var properties = obj.GetType().GetProperties();
            foreach (var propertyInfo in properties)
            
                if (!this.propertiesToIgnore.Contains(propertyInfo.Name))
                
                    if(this.ignoreNulls && propertyInfo.GetValue(obj, null) == null)
                    
                         continue;
                    
                    result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
                
            
            return result;
        

        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        
            throw new NotImplementedException(); //Converter is currently only used for ignoring properties on serialization
        
    

【讨论】:

逻辑上的小改动,PropertyExclusionConverter 可以变成PropertyInclusionConverter 这太棒了 一个潜在的问题是它必须在每次序列化对象时一遍又一遍地进行名称匹配和排除工作。但是,一旦编译,类型的属性就不会改变——您应该预先计算每个类型应该包含的名称,并在每一行上重用列表。对于非常庞大的 JSON 序列化作业,缓存可以显着提高性能。【参考方案6】:

如果您使用的是System.Text.Json,那么您可以使用[JsonIgnore]。 FQ:System.Text.Json.Serialization.JsonIgnoreAttribute

微软官方文档:JsonIgnoreAttribute

如here所述:

该库是 .NET Core 3.0 共享框架的一部分。 对于其他目标框架,安装 System.Text.Json NuGet 包裹。该软件包支持:

.NET Standard 2.0 及更高版本 .NET Framework 4.6.1 及更高版本 .NET Core 2.0、2.1 和 2.2

【讨论】:

【参考方案7】:

你也可以使用[NonSerialized]属性

[Serializable]
public struct MySerializableStruct

    [NonSerialized]
    public string hiddenField;
    public string normalField;

From the MS docs:

表示不应序列化可序列化类的字段。这个类不能被继承。


例如,如果您使用 Unity(这不仅适用于 Unity),那么它适用于 UnityEngine.JsonUtility

using UnityEngine;

MySerializableStruct mss = new MySerializableStruct 
 
    hiddenField = "foo", 
    normalField = "bar" 
;
Debug.Log(JsonUtility.ToJson(mss)); // result: "normalField":"bar"

【讨论】:

此属性对属性无效,这是 OP 询问的内容。【参考方案8】:

为 dotnet core 添加 System.Text.Json 版本

对于编译时间,请按照上述答案中的建议添加 [JsonIgnore]。

对于运行时,需要将 JsonConverter 添加到选项中。

首先,为要排除的类型创建一个JsonConverter,例如下面的ICollection&lt;LabMethod&gt;

public class LabMethodConverter : JsonConverter<ICollection<LabMethod>>

    public override ICollection<LabMethod> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    
        //deserialize JSON into a ICollection<LabMethod>
        return null;
    

    public override void Write(Utf8JsonWriter writer, ICollection<LabMethod> value, JsonSerializerOptions options)
    
        //serialize a ICollection<LabMethod> object
        writer.WriteNullValue();
    

然后在序列化Json的时候添加到options

var options = new JsonSerializerOptions();
options.Converters.Add(new LabMethodConverter());
var new_obj = Json(new  rows = slice, total = count , options);

【讨论】:

以上是关于如何从 Json 序列化中排除属性的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Swift Codable 中排除属性?

java 序列化时排除指定属性

根据GSON中的值从序列化中排除某些字段

序列化:如何排除 json 响应中的实体列,但不排除 Nestjs 中的内部查询

从春季安全会话序列化中排除属性?

JSON序列化(stringify)对象时排除某些属性的两种方法