如何忽略类中的属性如果为空,使用json.net

我使用Json。网将一个类序列化为JSON。

我的课程是这样的:

class Test1
{
[JsonProperty("id")]
public string ID { get; set; }
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("url")]
public string URL { get; set; }
[JsonProperty("item")]
public List<Test2> Test2List { get; set; }
}

我想添加一个JsonIgnore()属性Test2List属性只有当Test2Listnull。如果它不是空的,那么我想包括它在我的json。

536388 次浏览

正如James Newton King所说:如果你自己创建序列化器,而不是使用JavaScriptConvert,那么你可以设置忽略# EYZ0财产

下面是一个例子:

JsonSerializer _jsonWriter = new JsonSerializer {
NullValueHandling = NullValueHandling.Ignore
};

或者,按照@amit的建议

JsonConvert.SerializeObject(myObject,
Newtonsoft.Json.Formatting.None,
new JsonSerializerSettings {
NullValueHandling = NullValueHandling.Ignore
});

使用JsonProperty属性的替代解决方案:

[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
// or
[JsonProperty("property_name", NullValueHandling=NullValueHandling.Ignore)]


// or for all properties in a class
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]

如在这个在线文档中所见。

可以在他们的网站(http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx)上的这个链接中看到,我支持使用[Default()]来指定默认值

摘自链接

   public class Invoice
{
public string Company { get; set; }
public decimal Amount { get; set; }


// false is default value of bool
public bool Paid { get; set; }
// null is default value of nullable
public DateTime? PaidDate { get; set; }


// customize default values
[DefaultValue(30)]
public int FollowUpDays { get; set; }
[DefaultValue("")]
public string FollowUpEmailAddress { get; set; }
}




Invoice invoice = new Invoice
{
Company = "Acme Ltd.",
Amount = 50.0m,
Paid = false,
FollowUpDays = 30,
FollowUpEmailAddress = string.Empty,
PaidDate = null
};


string included = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { });


// {
//   "Company": "Acme Ltd.",
//   "Amount": 50.0,
//   "Paid": false,
//   "PaidDate": null,
//   "FollowUpDays": 30,
//   "FollowUpEmailAddress": ""
// }


string ignored = JsonConvert.SerializeObject(invoice,
Formatting.Indented,
new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });


// {
//   "Company": "Acme Ltd.",
//   "Amount": 50.0
// }

JSON。NET也尊重EmitDefaultValue属性上的DataMemberAttribute,以防你不想给你的模型添加特定于newtonsoft的属性:

[DataMember(Name="property_name", EmitDefaultValue=false)]

您可以这样做来忽略正在序列化的对象中的所有空值,因此任何空属性都不会出现在JSON中

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var myJson = JsonConvert.SerializeObject(myObject, settings);

@Mrchief / @amit的答案的改编,但适用于使用VB的人

 Dim JSONOut As String = JsonConvert.SerializeObject(
myContainerObject,
New JsonSerializerSettings With {
.NullValueHandling = NullValueHandling.Ignore
}
)
< p >看: # EYZ0 < / p >

https://msdn.microsoft.com/en-us/library/bb385125.aspx

稍微阐述一下GlennG非常有用的答案(将语法从c#翻译到VB。Net并不总是“显而易见”的),您还可以装饰单个类属性来管理如何处理空值。如果你这样做,不要使用GlennG建议的全局JsonSerializerSettings,否则它会覆盖单个装饰。如果您希望在JSON中出现一个空项,这样消费者就不必做任何特殊处理,那么这就很方便了。例如,如果消费者需要知道一个可选项数组通常是可用的,但目前是空的…… 属性声明中的修饰如下:

<JsonPropertyAttribute("MyProperty", DefaultValueHandling:=NullValueHandling.Include)> Public Property MyProperty As New List(of String)
对于那些你不想在JSON中出现的属性,将: = NullValueHandling。包括更改为: = NullValueHandling。忽略。 顺便说一下,我发现你可以很好地为XML和JSON序列化装饰属性(只是把它们放在一起)。这让我可以随意调用dotnet中的XML序列化器或NewtonSoft序列化器——两者都是并行工作的,我的客户可以选择使用XML或JSON。这就像门把手上的鼻涕一样光滑,因为我有客户两者都需要!< / p >

你可以写:[JsonProperty("property_name",DefaultValueHandling = DefaultValueHandling.Ignore)]

它还负责使用默认值(不仅仅是null)不序列化属性。例如,它对枚举很有用。

这里有一个类似的选项,但提供了另一种选择:

public class DefaultJsonSerializer : JsonSerializerSettings
{
public DefaultJsonSerializer()
{
NullValueHandling = NullValueHandling.Ignore;
}
}

然后,我这样使用它:

JsonConvert.SerializeObject(postObj, new DefaultJsonSerializer());

不同之处在于:

  • 通过在每个使用JsonSerializerSettings的地方实例化和配置JsonSerializerSettings来减少重复代码。
  • 节省配置要序列化的每个对象的每个属性的时间。
  • 仍然为其他开发人员提供了序列化选项的灵活性,而不是在可重用对象上显式指定属性。
  • 我的用例是代码是第三方库,我不想强迫那些想要重用我的类的开发人员使用序列化选项。
  • 潜在的缺点是它是其他开发人员需要了解的另一个对象,或者如果您的应用程序很小,这种方法对于单个序列化并不重要。
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
settings.NullValueHandling = NullValueHandling.Ignore;
//you can add multiple settings and then use it
var bodyAsJson = JsonConvert.SerializeObject(body, Formatting.Indented, settings);

在。net Core中,这就容易多了。在你的startup.cs中添加json选项,你可以在那里配置设置。


public void ConfigureServices(IServiceCollection services)


....


services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});


与Json。网

 public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> ReleaseCountries { get; set; }
}


Movie movie = new Movie();
movie.Name = "Bad Boys III";
movie.Description = "It's no Bad Boys";


string ignored = JsonConvert.SerializeObject(movie,
Formatting.Indented,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

结果将是:

{
"Name": "Bad Boys III",
"Description": "It's no Bad Boys"
}

使用System.Text.Json和。net Core 3.0,这对我来说是有效的:

var jsonSerializerOptions = new JsonSerializerOptions()
{
IgnoreNullValues = true
};
var myJson = JsonSerializer.Serialize(myObject, jsonSerializerOptions );

这并没有完全回答最初的问题,但根据用例可能证明是有用的。(因为我是在搜索之后才来到这里的,所以它可能对其他人有用。)

在我最近的经验中,我正在使用PATCH api。如果指定了一个属性但没有给定值(null/undefined,因为它是js),那么该属性和值将从正在修补的对象中移除。所以我在寻找一种方法来选择性地构建一个对象,它可以以这样一种方式序列化,这样就可以工作。

我记得看到过ExpandoObject,但直到今天才有一个真正的用例。这允许您动态地构建对象,因此您不会有null属性,除非您希望它们在那里。

在这里是一个工作提琴,代码如下。

结果:

Standard class serialization
noName: {"Name":null,"Company":"Acme"}
noCompany: {"Name":"Fred Foo","Company":null}
defaultEmpty: {"Name":null,"Company":null}
ExpandoObject serialization
noName: {"Company":"Acme"}
noCompany: {"name":"Fred Foo"}
defaultEmpty: {}

代码:

using Newtonsoft.Json;
using System;
using System.Dynamic;
                    

public class Program
{
public static void Main()
{
SampleObject noName = new SampleObject() { Company = "Acme" };
SampleObject noCompany = new SampleObject() { Name = "Fred Foo" };
SampleObject defaultEmpty = new SampleObject();
        

        

Console.WriteLine("Standard class serialization");
Console.WriteLine($"    noName: { JsonConvert.SerializeObject(noName) }");
Console.WriteLine($"    noCompany: { JsonConvert.SerializeObject(noCompany) }");
Console.WriteLine($"    defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty) }");
        

        

Console.WriteLine("ExpandoObject serialization");
Console.WriteLine($"    noName: { JsonConvert.SerializeObject(noName.CreateDynamicForPatch()) }");
Console.WriteLine($"    noCompany: { JsonConvert.SerializeObject(noCompany.CreateDynamicForPatch()) }");
Console.WriteLine($"    defaultEmpty: { JsonConvert.SerializeObject(defaultEmpty.CreateDynamicForPatch()) }");
}
}


public class SampleObject {
public string Name { get; set; }
public string Company { get; set; }
    

public object CreateDynamicForPatch()
{
dynamic x = new ExpandoObject();
        

if (!string.IsNullOrWhiteSpace(Name))
{
x.name = Name;
}
        

if (!string.IsNullOrEmpty(Company))
{
x.Company = Company;
}
        

return x;
}
}

或者像这样设置。

services.AddMvc().AddJsonOptions(options =>
options.JsonSerializerOptions.IgnoreNullValues = true;
});

在我的情况下,使用。net 6这是解决方案:

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]

更多信息在这里

< p >。净6 - 在Program.cs中添加代码。这将忽略类或记录属性,如果它为空
using System.Text.Json.Serialization;


var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers()
.AddJsonOptions(opts =>
{
var enumConverter = new JsonStringEnumConverter();
opts.JsonSerializerOptions.Converters.Add(enumConverter);
opts.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault | JsonIgnoreCondition.WhenWritingNull;
});