2015-04-15 26 views
4

在將數據返回給客戶端之前,我們將Asp.Net WebAPI與實體框架(使用延遲加載)並使用Json.net將數據序列化到json。json.net在序列化時限制maxdepth

我們正在經歷間歇性的內存使用突然激增,我們懷疑這可能源於json.net在序列化數據時不會識別引用循環(因爲Entity Framework可能會使用代理類進行一些延遲加載voodoo, .net)

我想我會限制Json.net被允許進入序列化數據的深度(至少在發生這種情況時我們會得到一個明智的異常,以便我們可以在數據模型中修復它),但是我很快發現JsonSerializerSettings的MaxDepth屬性只在解序列化對象時纔會使用。

是否有任何已知的方式在串行化時對json.net施加限制?

+0

如果你完全阻止循環引用的序列化,那麼這可能是一個選項嗎? –

+0

我們不知道我們是否有循環引用....這是問題(大型數據庫) – AndreasKnudsen

回答

1

我想不出用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); 
      json = null; 
      throw; 
     } 

由於您的代碼包含,如果您想在Web API調用中執行此操作,可以按照Rick Strahl的說明爲JSON創建自定義MediaTypeFormatterUsing an alternate JSON Serializer in ASP.NET Web API;然後在生成json字符串時使用OnWriteToStreamAsync方法中的上述代碼。