序列化时 Json.NET 限制 MaxDepth

标签 json.net lazy-loading asp.net-web-api

我们将 ASP.NET WebAPI 与 Entity Framework (延迟加载)一起使用,并在将数据返回给客户端之前使用 Json.NET 将数据序列化为 JSON。
我们正在经历内存使用量的间歇性突然激增,我们怀疑这可能源于 Json.NET 在序列化数据时无法识别引用循环(因为 Entity Framework 可能正在使用代理类进行一些延迟加载,而这些代理类不受 Json.NET 的关注)。
我以为我会限制 Json.NET 允许序列化数据的深度(至少当发生这种情况时我们会得到一个合理的异常,以便我们可以在数据模型中修复它),但我很快发现 MaxDepth JsonSerializerSettings 的属性仅在 时生效德 序列化对象。
序列化时是否有任何已知的方法对 Json.NET 施加限制?

最佳答案

我想不出用 Json.NET 开箱即用的方法,因为(正如您正确观察到的) MaxDepth 序列化时被忽略。你可以做的是子类化 JsonTextWriter 并自己做检查:

public class MaxDepthJsonTextWriter : JsonTextWriter
{
    public int? MaxDepth { get; set; }
    public int MaxObservedDepth { get; private set; }

    public MaxDepthJsonTextWriter(TextWriter writer, JsonSerializerSettings settings)
        : base(writer)
    {
        this.MaxDepth = (settings == null ? null : settings.MaxDepth);
        this.MaxObservedDepth = 0;
    }

    public MaxDepthJsonTextWriter(TextWriter writer, int? maxDepth)
        : base(writer)
    {
        this.MaxDepth = maxDepth;
    }

    public override void WriteStartArray()
    {
        base.WriteStartArray();
        CheckDepth();
    }

    public override void WriteStartConstructor(string name)
    {
        base.WriteStartConstructor(name);
        CheckDepth();
    }

    public override void WriteStartObject()
    {
        base.WriteStartObject();
        CheckDepth();
    }

    private void CheckDepth()
    {
        MaxObservedDepth = Math.Max(MaxObservedDepth, Top);
        if (Top > MaxDepth)
            throw new JsonSerializationException(string.Format("Depth {0} Exceeds MaxDepth {1} at path \"{2}\"", Top, MaxDepth, Path));
    }
}

然后,要手动生成 JSON 字符串,您可以像这样使用它:

var settings = new JsonSerializerSettings { MaxDepth = 10 };
string json;
try
{
    using (var writer = new StringWriter())
    {
        using (var jsonWriter = new MaxDepthJsonTextWriter(writer, settings))
        {
            JsonSerializer.Create(settings).Serialize(jsonWriter, myClass);
            // Log the MaxObservedDepth here, if you want to.
        }
        json = writer.ToString();
    }
    Debug.WriteLine(json);
}
catch (Exception ex)
{
    Debug.WriteLine(ex);
    throw;
}

演示 fiddle here .

由于您的标签包含 ,如果您想在 Web API 调用中执行此检查,您可以按照 Rick Strahl 的说明创建自定义 MediaTypeFormatter对于 JSON:Using an alternate JSON Serializer in ASP.NET Web API ;然后在 OnWriteToStreamAsync 中使用上面的代码生成json字符串时的方法。

关于序列化时 Json.NET 限制 MaxDepth,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29651433/

相关文章:

ios - 带有初始值设定项的惰性属性

jquery - 如何使用 BXSlider 进行延迟加载

json - 为什么转储此 JObject 会在 LINQPad 中引发 AmbiguousMatchException?

c# - 反序列化不同类型的JSON数组

Angular(5) - 延迟加载和 canActivate 守卫 - StaticInjectorError

angularjs - 如何与 http 和 https 同时运行 Angularjs webapi?

c# - ASP.NET Core 中基于 token 的身份验证

c# - Web API 单元测试未按预期工作

c# - 在没有自引用循环的地方检测到自引用循环

c# - 如何检索路径为动态的属性的 json 值