JSON 序列化程序如何忽略导航属性?

Posted

技术标签:

【中文标题】JSON 序列化程序如何忽略导航属性?【英文标题】:How can I do JSON serializer ignore navigation properties? 【发布时间】:2019-08-02 16:34:48 【问题描述】:

我和这个问题完全一样: How do I make JSON.NET ignore object relationships?

我看到了建议的解决方案,我知道我必须使用 Contract Revolver,我也看到了 Contract Resolver 的代码,但我不知道如何使用它。

我应该在 WebApiConfig.vb 中使用它吗? 我还是应该修改我的实体模型吗?

【问题讨论】:

如果你和我的情况一样,这里是我的建议:忘记它,将你的控制器更改为 OData。完美运行,JSON序列化器没有问题。 卡洛斯,我的波纹管解决方案有效,您可以将其标记为正确答案吗? 我已经标记了你的答案,RAM,因为它有一些支持,所以它必须工作。但我对此发表评论是因为它可能很有用(如果对我来说)。在构造函数中,Configuration.LazyLoadingEnabled 成功了: public ExampleController() db.Configuration.LazyLoadingEnabled = false; 谢谢。我的答案也适用于TrueFalse 属性的LazyLoadingEnabled 值。 【参考方案1】:

这是一个有用的问题?希望对您有所帮助:

A)

如果您手动创建了模型(没有Entity Framework),首先将关系属性标记为virtual

如果您的模型是由EF 创建的,它已经为您完成了,每个Relation Property 都标记为virtual,如下所示:

Sample class:

public class PC

    public int FileFolderId get;set;

    public virtual ICollection<string> Libs  get; set; 
    public virtual ICollection<string> Books  get; set; 
    public virtual ICollection<string> Files  get; set; 

B)

JSON 序列化程序现在可以忽略这些关系属性,方法是使用以下 ContractResolver for JSON.NET

CustomResolver:

class CustomResolver : DefaultContractResolver

    private readonly List<string> _namesOfVirtualPropsToKeep=new List<string>(new String[]);

    public CustomResolver()

    public CustomResolver(IEnumerable<string> namesOfVirtualPropsToKeep)
    
        this._namesOfVirtualPropsToKeep = namesOfVirtualPropsToKeep.Select(x=>x.ToLower()).ToList();
    

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    
        JsonProperty prop = base.CreateProperty(member, memberSerialization);
        var propInfo = member as PropertyInfo;
        if (propInfo != null)
        
            if (propInfo.GetMethod.IsVirtual && !propInfo.GetMethod.IsFinal
                && !_namesOfVirtualPropsToKeep.Contains(propInfo.Name.ToLower()))
            
                prop.ShouldSerialize = obj => false;
            
        
        return prop;
    

C)

最后,使用上面的ContractResolver 轻松序列化您的模型。像这样设置它:

// -------------------------------------------------------------------
// Serializer settings
JsonSerializerSettings settings = new JsonSerializerSettings

    // ContractResolver = new CustomResolver();
    // OR:
    ContractResolver = new CustomResolver(new []
    
        nameof(PC.Libs), // keep Libs property among virtual properties
        nameof(PC.Files) // keep Files property among virtual properties
    ),
    PreserveReferencesHandling = PreserveReferencesHandling.None,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Formatting = Formatting.Indented
;

// -------------------------------------------------------------------
// Do the serialization and output to the console
var json = JsonConvert.SerializeObject(new PC(), settings);
Console.WriteLine(json);

// -------------------------------------------------------------------
// We can see that "Books" filed is ignored in the output:
// 
//  "FileFolderId": 0,
//  "Libs": null,
//  "Files": null
// 

现在,所有导航(关系)属性 [virtual 属性] 将被自动忽略,除非您通过在代码中确定它们来保留其中一些。?

Live DEMO


感谢@BrianRogers 的回答here。

【讨论】:

你是个救命恩人!! 这是一个很好的答案。 @RAM,您是否知道有条件地仅包含特定虚拟集合的方法,可以通过自定义注释或其他方式? @Janne,我更新了我的答案以支持保留某些属性的名称(尽管我们也可以基于属性制定解决方案)。我还添加了一个 Live Demo 的链接。 ? 感谢分享@RAM,我会在以后的计划中考虑到这一点。 ... 只是一个快速通知@RAM,*** 上的代码示例是部分的,因为它缺少对 _namesOfVirtualPropsToKeep 的处理(只是 IF 语句的一个条件),但 Live DEMO 包含这个缺失的壮举。只是想让你知道。感谢您的解决方案!【参考方案2】:

如果您使用的是Newtonsoft.Json

标记字段
Newtonsoft.Json.JsonIgnore

而不是

System.Text.Json.Serialization.JsonIgnore

【讨论】:

以上是关于JSON 序列化程序如何忽略导航属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Json.Net 在不忽略子属性的情况下从 documentDB 序列化/反序列化动态/通用对象?

有没有一种方法可以使JavaScriptSerializer忽略某些通用类型的属性?

在使用 Jackson 反序列化期间选择性地忽略 JSON 属性

将 xml 数据序列化为 json 时忽略命名空间属性

如何从 C# 控制器(OData)的 JSON 序列化中修复丢失的子对象(导航属性)?

配置 JSON.NET 以忽略 DataContract/DataMember 属性