解析JSON、擴展Fiddler
按文章結構,這部分應該給出WCFRest項目示例,我想WinForm示例足夠詳盡了,況且WCFRest還不需要使用插件AppDomain那一套,於是把最近寫的Fiddler擴展搬上來吧。
Fiddler有一套自成的插件系統,可以在其官方網站找到完整文檔(戳這里)。通過其提供的一整套接口,我們可以從界面至功能全方位擴展它。這里主題簡單,我們只為其添加一個JSON解析界面。
PART I:JSON解析
Mgen有一個JSON解析范例(戳這里)代碼相當好看,WPF模塊綁定也很強大。這里使用Json.com的一個示例稍作修改,解析效果如下:
上述代碼過於忠實地體現了Newtonsoft的設計,只有JValue被解析成葉節點,其他JToken對象全部是枝節點,解析出來的JSON樹層次太深可讀性不夠好。
Newtonsoft中JSON結構:
這里重新設計結構圖如下:
一共有4種節點:指示值的JsonValueNode葉節點、指示鍵值對的JsonPropertyNode的葉節點,指示數組的JsonArrayNode枝節點,及指示對象的JsonObjectNode的樹節點。解析時關鍵在對JProperty的處理:把Value為JValue的JProperty對象解析成JsonPropertyNode葉節點,Value為JContainer的JProperty視子節點屬性實例成JsonArrayNode或JsonObjectNode樹節點,初步代碼如下:
public class JsonNode { public IEnumerable<JsonNode> Children { get; internal set; } internal JsonNode() { } } public class JsonValueNode : JsonNode { public Object Value { get; private set; } public JsonValueNode(Object value) { Value = value; } public override String ToString() { return Value != null ? Value.ToString() : "<null>"; } } public class JsonPropertyNode : JsonNode { public String Name { get; private set; } public Object Value { get; private set; } public JsonPropertyNode(String name, Object value) { Name = name; Value = value; } public override String ToString() { return String.Concat(Name, " : ", (Value != null ? Value.ToString() : "<null>")); } } public class JsonArrayNode : JsonNode { public String Name { get; private set; } public JsonArrayNode(String name) { Name = name ?? "[]"; } public override String ToString() { return Name; } } public class JsonObjectNode : JsonNode { public String Name { get; private set; } public JsonObjectNode(String name) { Name = name ?? "{}"; } public override String ToString() { return Name; } }
JsonNodeFactory作為JsonNode的建造者:
public class JsonNodeFactory { public static JsonNode CreateFromJToken(JToken jtoken) { if (jtoken is JValue) { return new JsonValueNode(((JValue)jtoken).Value); } else if (jtoken is JProperty) { JProperty jproperty = (JProperty)jtoken; if (jproperty.Value is JValue) { return new JsonPropertyNode(jproperty.Name, ((JValue)jproperty.Value).Value); } else if (jproperty.Value is JArray) { JsonArrayNode jsonNode = new JsonArrayNode(jproperty.Name); jsonNode.Children = ((JArray)jproperty.Value).Children().Select(n => CreateFromJToken(n)); return jsonNode; } else if (jproperty.Value is JObject) { JsonObjectNode jsonNode = new JsonObjectNode(jproperty.Name); jsonNode.Children = ((JObject)jproperty.Value).Children().Select(n => CreateFromJToken(n)); return jsonNode; } else { throw new Exception("Unknown JProperty"); } } else if (jtoken is JArray) { JsonArrayNode jsonNode = new JsonArrayNode(null); jsonNode.Children = ((JArray)jtoken).Children().Select(n => CreateFromJToken(n)); return jsonNode; } else if (jtoken is JObject) { JsonObjectNode jsonNode = new JsonObjectNode(null); jsonNode.Children = ((JObject)jtoken).Children().Select(n => CreateFromJToken(n)); return jsonNode; } else { throw new Exception("Unknown jtoken"); } } }
文章后面的代碼文件中更具體的實現加入了父節點與索引,ToString()邏輯更完備。客戶端調用:
class Program { static void Main(string[] args) { JToken jtoken = JToken.Parse(System.IO.File.ReadAllText("json.txt")); JsonNode node = JsonNodeFactory.CreateFromJToken(jtoken); Debug.Listeners.Add(new TextWriterTraceListener(Console.Out)); Display(node); } private static void Display(JsonNode node) { Debug.WriteLine(node); if (node.Children != null) { Debug.Indent(); foreach (JsonNode sub in node.Children) { Display(sub); } Debug.Unindent(); } } }
json.txt見截圖與后文代碼文件,新的解析結構:
PART2:Fiddler插件
Fiddler自帶的JSON顯示是一個簡單的Tree,無法完成復雜功能。Codeplex上有一個JsonView項目(戳這里),Fiddler子項目丟到%Program Files%/Fiddler/Inspectors目錄即可。問題在於它有BUG,且使用Newtonsoft的Json.Net版本極其低。沒辦法,重寫一個。這里有2處需要注意:
1. 需要添加Public類,實現Inspector2、IResponseInspector2,抽象類Inspector2.AddToTab(TabPage o)是UI呈現方法,headers與body屬性內部可以完成對自定義控件賦值;
2. 需要加入[assembly: Fiddler.RequiredVersion("x.x.x.x")]特性,位置不限。Fiddler目錄有基於.Net Framework 2.0和4.0的版本,本例使用4.0,CLR版本兼容性、X64兼容性等具體內容請自行翻閱文檔。
AddToTab方法大致內容如下:
public override void AddToTab(TabPage tabPage) { utrlJson = new UserControl_JsonView() { Dock = DockStyle.Fill }; tabPage.Text = "MyJson"; tabPage.Controls.Add(utrlJson); }
這里使用了一個UserControl,暴露一個Content屬性,內部使用TextBox和TreeView展示Json文本與JsonNode結構。
取消Fiddler引用及排除Plugin.cs,將項目類型設置為Windows應用程序,可以得到Form窗體程序;加入引用及Plugin.cs,將項目類型設置成類庫,扔到%Program Files%/Fiddler/Inspectors目錄便是Fiddler插件。這里加入了文本定位、節點分層展開、節點值復制(可以在TreeView上使用Ctrl+C進行智能復制)等方法,方便使用。
PART3:后記
感覺代碼還是比較亂,JsonNode創建方法還可以提煉;水平所限,TextBox光標定位正則不夠強大,需要優化;功能上講,可以加入設置項以組織編碼格式、Header解析、控件視圖等。代碼文件及二進制文件(戳這里)奉上。