• 解析JSON、扩展Fiddler


    解析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解析、控件视图等。代码文件及二进制文件(戳这里)奉上。

  • 相关阅读:
    IOS和Android支持的音频编解码
    IOS XIB Cell自适应高度实现
    IOS竖屏应用单个页面横屏的解决办法
    FMDB读取Datetime类型值为1970的问题
    一些IOS开发中的小技巧
    IOS的一些小技巧
    Static块详解
    Hadoop学习笔记3---安装并运行Hadoop
    Hadoop学习笔记2---配置详解
    同一账户在同一时间 只能登陆一次
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3167583.html
Copyright © 2020-2023  润新知