zoukankan      html  css  js  c++  java
  • JavaScriptSerializer的使用, 今上午琢磨了半天, 小结一下.

    需求场景:

     当用户在页面上点击"编辑"按钮时, 将生成一个自定义对象集合(List<JenkinsTask>), 之后遍历该集合中的所有任务, 依次启动Jenkins的构建任务.

    同时, aspx页面上放有一个Ajax的Timer空间, Timer每5秒触发一次. 每次触发Timer的时候, 遍历List<JenkinsTask>集合, 将任务执行结果显示在页面的文本框中.

    该功能已经由Javascrit实现了, 但是本机调试正常, 客户机有的正常、有的异常, 而且出错的情况还各不相同. 于是, 在服务器端, 重新实现一下该功能.

    问题:

    HTTP协议的无状态特性, 将无法保存List<JenkinsTask>集合, 所以想到序列化该集合并将之保存在ViewState中, C#提供的序列化器有BinaryFormatter、SoapFormatter, 前者以二级制形式序列化对象, 后者以Soap协议格式序列化对象; 还有XML也提供了序列化器. 虽然本次是在服务器段实现该功能, 但考虑到将来可能还会再改到javascript的实现形式, 希望采用Json格式的序列化器.

    Json格式序列化器有两种实现System.Runtime.Serialization.Json名空间下的DataContractJsonSerializer类, 和System.Web.Script.Serialization命名空间下的JavaScriptSerializer类, 前者的过程类似于BinaryFormatter的序列化过程, 需要设计IO流等等, 而JavaScriptSerializer类相对就简单的多, 也不需要添加[Serializable]等Attribute特性字段.

    实现: (注意: 简单自定义类 和 复杂自定义类 的操作不同), 解决方案摘取的代码, 不完整, 还忘见谅.

    1. 引用System.Web.Script.Serialization命名空间;

    //页面中的Ajax控件Timer

    View Code
        <asp:Timer ID="timerJenkins" runat="server" ontick="timerJenkins_Tick" Enabled="false" Interval="5000">
    </asp:Timer>
    <asp:UpdatePanel ID="UpdatePanel2" runat="server">
    <Triggers>
    <asp:AsyncPostBackTrigger ControlID="timerJenkins" EventName="Tick" />
    </Triggers>
    <ContentTemplate>
    <table class="infoTable">
    <tr runat="server" id="trAppResult">
    <td class="infoTital">
    </td>
    <td class="infoContent">
    <div runat="server" id="divBuildResult" style=" 700px;">
    &nbsp;
    </div>
    <div runat="server" id="divBuildResultStatus" style=" 700px;">
    </div>
    </td>
    </tr>
    </table>
    <div id="divButton">
    <asp:Button ID="btn" runat="server" Text="" OnClientClick="return false;" Width="0"
    Height
    ="0" />
    <asp:Button ID="btnStructure" runat="server" Text="编译" CssClass="btn_mouseout" onmouseover="this.className='btn_mouseover'"
    onmouseout
    ="this.className='btn_mouseout'" onmousedown="this.className='btn_mousedown'"
    onmouseup
    ="this.className='btn_mouseup'" Style="margin-left: 30px; margin-right: 15px;"
    OnClick
    ="btnStructure_Click" />
    <asp:Button ID="btnSubmit" runat="server" Text="提交" OnCommand="btnSubmit_Click" CssClass="btn_mouseout"
    onmouseover
    ="this.className='btn_mouseover'" onmouseout="this.className='btn_mouseout'"
    onmousedown
    ="this.className='btn_mousedown'" onmouseup="this.className='btn_mouseup'"
    Style
    ="margin-right: 15px;" />
    <asp:Button ID="btnReturn" runat="server" Text="返回" OnClientClick="location.href='DevelopmentApplyList.aspx';return false;"
    CssClass
    ="btn_mouseout" onmouseover="this.className='btn_mouseover'" onmouseout="this.className='btn_mouseout'"
    onmousedown
    ="this.className='btn_mousedown'" onmouseup="this.className='btn_mouseup'" />
    </div>
    </ContentTemplate>
    </asp:UpdatePanel>

    2. 对于简单的自定义类(类成员多为简单数据类型), 再点击按钮的事件中创建List集合对象, 使用new JavaScriptSerializer().Serialize()即可完成序列化, 在Ajax的Timer控件后台方法中, 使用new JavaScriptSerializer().Deserialize()即可完成反序列化.

    实例如下:

    //JenkinsTast.cs

    View Code
    namespace WebSite.Common
    {
    public class JenkinsTask
    {
    private static readonly string JenkinsBaseUrl = ConfigurationManager.AppSettings["JenkinsPath"];
    private static readonly string JenkinsUrlFormat = JenkinsBaseUrl+"/job/{0}";
    private static readonly string JenkinsStartUrlFormat = JenkinsUrlFormat + "/build?delay=0sec";
    private static readonly string JenkinsResponseUrlFormat = JenkinsUrlFormat + "/buildHistory/ajax";
    private static readonly string JenkinsNoticeInfoStart = "构建任务< {0} >已启动...";
    private static readonly string JenkinsNoticeInfoRun = "构建任务< {0} >正在执行...";

        public JenkinsTask()
    { }


    public JenkinsTask(string structureName)
    {
    this.StructureTaskName = structureName;
    this.StructureTaskStatus = Enum.GetName(typeof(JenkinsTaskStatus), JenkinsTaskStatus.Init);
    }

    public string StructureTaskName { get; set; }
    public string StructureTaskStatus { get; set; }
    public int LastStructureId { get; set; }
    public string TarPackageName { get; set; }
    public string OutputHTML { get; set; }
    public string OutputText { get; set; }

    //启动构建任务
    public void StartJenkinsTask()
    {
    //获取构建任务ID
    string strId = getLastStructureId(XSSAccessHelper.GetJenkinsResponse(new Uri(string.Format(JenkinsUrlFormat, this.StructureTaskName)), "GET", null));
    int id = 0;
    if (!string.IsNullOrEmpty(strId))
    {
    id = Convert.ToInt32(strId);
    }
    //启动构建任务
    XSSAccessHelper.GetJenkinsResponse(new Uri(string.Format(JenkinsStartUrlFormat, this.StructureTaskName)), "GET", null);

    //获取构建任务信息, 将结果填入OutputHTML(Web异步无法启动, 这里改为只填写最近一次构建任务的ID)
    //GetStructureResponseInfo(id+1);
    this.LastStructureId = id + 1;

    this.OutputText = string.Format(JenkinsNoticeInfoStart,this.StructureTaskName);
    }

    private string getLastStructureId(string responseHTML)
    {
    string result = "";
    string regId = "<\\s*a\\s*href=\"lastBuild/\">Last\\s+build\\s*\\(#\\d+\\)\\s*,[\\W\\w]+?<\\s*\\/\\s*a\\s*>";
    Regex reg = new Regex(regId,RegexOptions.IgnoreCase);
    if(reg.IsMatch(responseHTML))
    {
    try
    {
    result = reg.Match(responseHTML).Value;
    result = result.Substring(result.IndexOf("#")+1, result.IndexOf(")") - result.IndexOf("#")-1);
    }
    catch
    {
    throw;
    }
    }
    return result;
    }

    //获取构建任务信息, 将结果填入OutputHTML
    public void GetStructureResponseInfo()
    {
    this.OutputHTML = XSSAccessHelper.GetJenkinsResponse(new Uri(string.Format(JenkinsResponseUrlFormat, this.StructureTaskName)), "n:" + this.LastStructureId.ToString(), "GET", null);
    this.OutputText = string.Format(JenkinsNoticeInfoRun, this.StructureTaskName);
    }
    }

    public enum JenkinsTaskStatus
    {
    Init = 0,
    CompileRunning = 1,
    CompileFinish = 2,
    PackageRunning = 3,
    PackageFinish = 4
    }
    }

    //Test.aspx.cs

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    using System.Web.Script.Serialization;

    namespace WebSite
    {
    public partial class TestUCPage_TEST_ : Page
    {
    protected void Page_Load(object sender, EventArgs e)
    {
    if (!this.IsPostBack)
    {
    HttpRequest req = HttpContext.Current.Request;
    }
    }

    protected void btnStructure_Click(object sender, EventArgs e)
    {
    this.btnSubmit.Enabled = false;
    if (this.chkEnvironment.SelectedItem == null)
    {
    this.chkEnvironment.BackColor = System.Drawing.Color.FromName("#FEB8B8");
    return;
    }
    else
    {
    this.chkEnvironment.BackColor = System.Drawing.Color.FromName("#FFFFFF");
    }

    //生成构建任务列表
    if (!string.IsNullOrEmpty(this.hiddenFldStructureList.Value))
    {
    JenkinsTask jt = new JenkinsTask(this.hiddenFldStructureList.Value);
    saveJenkinsTaskList(jt);
              this.timerJenkins.Enabled = true;        
            }
    }

    protected void timerJenkins_Tick(object sender, EventArgs e)
    {
    JenkinsTask jt = getJenkinsTaskList();
    if (jt != null)
    {
    this.divResult.innerHTML = jt.OutHtml;
    }
           saveJenkinsTaskList(jt); 
    }

            private JenkinsTask getJenkinsTaskList()
            {
                return new JavaScriptSerializer().Deserialize<JenkinsTask>(ViewState["JenkinsTaskList"].ToString());
            }

            private void saveJenkinsTaskList(JenkinsTask jt)
            {
                ViewState["JenkinsTaskList"] = new JavaScriptSerializer().Serialize(jt);
            }

        }
    }


    这样就已经可以了, 使用默认的JavaScriptConverter实现时, 必须要一个无参的构造函数.

    3. 对于复杂的自定义类型(含有自定义类成员, 或没有无参构造函数, 或私有写属性.....等等). 对于复杂类型, 默认的JavaScriptConverter会造成序列化或反序列化无法正常工作, 此时需要自己实现JavaScriptConverter(抽象类), 来完成序列化和反序列过程.

    //Jenkins.cs, 类中属性的Set方法为private, 且没有默认构造函数

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    using System.Configuration;
    using System.Text.RegularExpressions;
    using System.Runtime.Serialization;
    using System.Web.Script.Serialization;
    //using System.Security.Permissions;

    namespace WebSite.Common
    {
    public class JenkinsTask
    {
    private static readonly string JenkinsBaseUrl = ConfigurationManager.AppSettings["JenkinsPath"];
    private static readonly string JenkinsUrlFormat = JenkinsBaseUrl+"/job/{0}";
    private static readonly string JenkinsStartUrlFormat = JenkinsUrlFormat + "/build?delay=0sec";
    private static readonly string JenkinsResponseUrlFormat = JenkinsUrlFormat + "/buildHistory/ajax";
    private static readonly string JenkinsNoticeInfoStart = "构建任务< {0} >已启动...";
    private static readonly string JenkinsNoticeInfoRun = "构建任务< {0} >正在执行...";

    public JenkinsTask(string structureName)
    {
    this.StructureTaskName = structureName;
    this.StructureTaskStatus = Enum.GetName(typeof(JenkinsTaskStatus), JenkinsTaskStatus.Init);
    }

    public JenkinsTask(string structureName, JenkinsTaskStatus structureStatus, int structureId, string outHtml, string outText)
    {
    this.StructureTaskName = structureName;
    this.StructureTaskStatus = Enum.GetName(typeof(JenkinsTaskStatus),structureStatus);
    this.LastStructureId = structureId;
    this.OutputHTML = outHtml;
    this.OutputText = outText;
    }

    public string StructureTaskName { get; private set; }
    public string StructureTaskStatus { get; private set; }
    public int LastStructureId { get; private set; }
    public string TarPackageName { get; private set; }
    public string OutputHTML { get; private set; }
    public string OutputText { get; private set; }

    //启动构建任务
    public void StartJenkinsTask()
    {
    //获取构建任务ID
    string strId = getLastStructureId(XSSAccessHelper.GetJenkinsResponse(new Uri(string.Format(JenkinsUrlFormat, this.StructureTaskName)), "GET", null));
    int id = 0;
    if (!string.IsNullOrEmpty(strId))
    {
    id = Convert.ToInt32(strId);
    }
    //启动构建任务
    XSSAccessHelper.GetJenkinsResponse(new Uri(string.Format(JenkinsStartUrlFormat, this.StructureTaskName)), "GET", null);

    //获取构建任务信息, 将结果填入OutputHTML(Web异步无法启动, 这里改为只填写最近一次构建任务的ID)
    //GetStructureResponseInfo(id+1);
    this.LastStructureId = id + 1;

    this.OutputText = string.Format(JenkinsNoticeInfoStart,this.StructureTaskName);
    }

    private string getLastStructureId(string responseHTML)
    {
    string result = "";
    string regId = "<\\s*a\\s*href=\"lastBuild/\">Last\\s+build\\s*\\(#\\d+\\)\\s*,[\\W\\w]+?<\\s*\\/\\s*a\\s*>";
    Regex reg = new Regex(regId,RegexOptions.IgnoreCase);
    if(reg.IsMatch(responseHTML))
    {
    try
    {
    result = reg.Match(responseHTML).Value;
    result = result.Substring(result.IndexOf("#")+1, result.IndexOf(")") - result.IndexOf("#")-1);
    }
    catch
    {
    throw;
    }
    }
    return result;
    }

    //获取构建任务信息, 将结果填入OutputHTML
    public void GetStructureResponseInfo()
    {
    this.OutputHTML = XSSAccessHelper.GetJenkinsResponse(new Uri(string.Format(JenkinsResponseUrlFormat, this.StructureTaskName)), "n:" + this.LastStructureId.ToString(), "GET", null);
    this.OutputText = string.Format(JenkinsNoticeInfoRun, this.StructureTaskName);
    }
    }

    public enum JenkinsTaskStatus
    {
    Init = 0,
    CompileRunning = 1,
    CompileFinish = 2,
    PackageRunning = 3,
    PackageFinish = 4
    }

    /// <summary>
    /// 单个Jenkins任务的序列化和反序列化
    /// </summary>
    public class JenkinsTaskConverter : JavaScriptConverter
    {
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
    IDictionary<string, object> dict = new Dictionary<string, object>();
    if (obj != null)
    {
    JenkinsTask jt = obj as JenkinsTask;
    dict["StructureTaskName"] = jt.StructureTaskName;
    dict["StructureTaskStatus"] = jt.StructureTaskStatus;
    dict["LastStructureId"] = jt.LastStructureId;
    dict["OutputHTML"] = jt.OutputHTML;
    dict["OutputText"] = jt.OutputText;
    }
    return dict;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
    return new JenkinsTask(Convert.ToString(dictionary["StructureTaskName"]), (JenkinsTaskStatus)Enum.Parse(typeof(JenkinsTaskStatus), Convert.ToString(dictionary["StructureTaskStatus"])), Convert.ToInt32(dictionary["LastStructureId"]), Convert.ToString(dictionary["OutputHTML"]), Convert.ToString(dictionary["OutputText"]));
    }

    public override IEnumerable<Type> SupportedTypes
    {
    get
    {
    yield return typeof(JenkinsTask);
    }
    }
    }

    /// <summary>
    /// Jenkins任务集合的序列化和反序列化, 测试代码, 此处只提供个针对 序列化复杂类集合 的思路...
    /// </summary>
    //public class JenkinsTaskListConverter : JavaScriptConverter
    //{
    // public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    // {
    // IDictionary<string, object> dict = new Dictionary<string, object>();
    // if (obj != null)
    // {
    // List<JenkinsTask> jtLst = obj as List<JenkinsTask>;
    // if (jtLst != null && jtLst.Count > 0)
    // {
    // dict["JenkinsTaskCollection"] = jtLst;
    // }
    // //dict["ItemCount"] = jtLst.Count;
    // }
    // return dict;
    // }

    // public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    // {
    // return dictionary["JenkinsTaskCollection"] as List<JenkinsTask>;
    // }

    // public override IEnumerable<Type> SupportedTypes
    // {
    // get { yield return typeof(List<JenkinsTask>); }
    // }
    // }
    }

     //Test.aspx.cs, 注意在Page_Load时候注册了自定义的JavaScriptConverter转换器

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    using System.Web.Script.Serialization;

    namespace WebSite
    {
    public partial class TestUCPage_TEST_ : Page
    {
            protected void Page_Load(object sender, EventArgs e)
    {

            JavaScriptSerializer jss = new JavaScriptSerializer();

           //注册JenkinsTask转换器
     jss.RegisterConverters(new JenkinsTaskConverter[] { new JenkinsTaskConverter() });

    if (!this.IsPostBack)
    {
    HttpRequest req = HttpContext.Current.Request;
    }
    }

    protected void btnStructure_Click(object sender, EventArgs e)
    {
    this.btnSubmit.Enabled = false;
    if (this.chkEnvironment.SelectedItem == null)
    {
    this.chkEnvironment.BackColor = System.Drawing.Color.FromName("#FEB8B8");
    return;
    }
    else
    {
    this.chkEnvironment.BackColor = System.Drawing.Color.FromName("#FFFFFF");
    }

    //生成构建任务列表
    if (!string.IsNullOrEmpty(this.hiddenFldStructureList.Value))
    {
    JenkinsTask jt = new JenkinsTask(this.hiddenFldStructureList.Value);
    saveJenkinsTaskList(jt);
               this.timerJenkins.Enabled = true;
    }
    }

    protected void timerJenkins_Tick(object sender, EventArgs e)
    {
            this.timerJenkins.Enabled = false;
    JenkinsTask jt = getJenkinsTaskList();
    if (jt != null)
    {
    this.divResult.innerHTML = jt.OutHtml;
    }
            saveJenkinsTaskList(jt);
            this.timerJenkins.Enabled = true;
    }

            private JenkinsTask getJenkinsTaskList()
            {

                return jss.Deserialize<JenkinsTask>(ViewState["JenkinsTaskList"].ToString());
            }

            private void saveJenkinsTaskList(JenkinsTask jt)
            {

                ViewState["JenkinsTaskList"] = jss.Serialize(jt);
            }

        }
    }

     总结:

    额外的, 在Javascript中, 是可以读取隐藏域中的  序列化后的内容的, 这样的就能在JS中用eval("("+strSerialize+")")获得JSon对象.

    对于今天上午遇到的场景, 其实用 列1中, 所描述的"简单类型"的情形, 就能解决问题. 之所以, 引出后边的东东, 是因为开始时候JenkinsTask任务中, 没有写默认构造函数, 其中的几个属性也是Set访问器也是private的, 所以一直无法反序列化成功. 虽然犯了回低级错误, 但是对这几个序列化器的内容梳理的一边, 标记下也算没白费功夫.

    //服务端跨站访问Jenkins的代码, 服务端实现的访问Jenkis的代码, 与本贴主题无关, 标记一下

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    using System.Text.RegularExpressions;
    using System.Configuration;
    using System.Net;
    using System.IO;
    using System.Text;

    namespace WebSite.Common
    {
    public class XSSAccessHelper
    {
    private static readonly string jenkinsUrl = ConfigurationManager.AppSettings["JenkinsPath"];
    private static readonly string jenkinsName = ConfigurationManager.AppSettings["JenkinsName"];
    private static readonly string jenkinsPwd = ConfigurationManager.AppSettings["JenkinsPwd"];

    public static string GetJenkinsResponse(Uri url, string requestType, string postRequestBody)
    {
    return GetJenkinsResponse(url, null, requestType, postRequestBody);
    }

    /// <summary>
    /// 从Jenkins上获取返回值信息
    /// </summary>
    /// <param name="url">请求的Jenkins地址</param>
    /// <param name="requestHeader">自定义的请求头, 每个请求头为以":"分隔的名值对, 多个名值对之间以","分隔</param>
    /// <param name="requestType">请求头类型("GET" or "POST")</param>
    /// <param name="postRequestBody">POST类型的请求包体, 可为NULL或空字符串</param>
    /// <returns>从Jenkins上返回的HTML信息(已去除回车换行)</returns>
    public static string GetJenkinsResponse(Uri url,string requestHeader,string requestType, string postRequestBody)
    {
    string responseHTML = "";
    #region SetRequest
    HttpWebRequest hwRequest = getJenkinsRequest(url);
    hwRequest.Method = requestType;
    if (!string.IsNullOrEmpty(requestHeader))
    {
    foreach (string str in requestHeader.Split(','))
    {
    if (!string.IsNullOrEmpty(str))
    hwRequest.Headers.Add(str);
    }
    }
    if(requestType == "POST")
    {
    //异步请求必须添加ContentType请求头
    hwRequest.ContentType = "application/x-www-form-urlencoded";
    //请求包体
    if (!string.IsNullOrEmpty(postRequestBody))
    {
    byte[] postBodyBytes = Encoding.Default.GetBytes(postRequestBody);//传递的值
    hwRequest.ContentLength = postBodyBytes.Length;
    //把传递的值写到流中
    using (Stream requestStream = hwRequest.GetRequestStream())
    {
    try
    {
    requestStream.Write(postBodyBytes, 0, postBodyBytes.Length);
    }
    catch (Exception ex)
    {
    throw ex;
    }
    }
    }
    }
    #endregion

    #region GetResponse
    using (HttpWebResponse hwrResponse = hwRequest.GetResponse() as HttpWebResponse)
    using (Stream responseStream = hwrResponse.GetResponseStream())
    using (StreamReader sReader = new StreamReader(responseStream, Encoding.UTF8))
    {
    try
    {
    responseHTML = formatHtml(sReader.ReadToEnd());
    }
    catch (Exception ex)
    {
    throw ex;
    }
    }
    return responseHTML;
    #endregion
    }


    private static HttpWebRequest getJenkinsRequest(Uri requestUrl)
    {
    CredentialCache cCache = new CredentialCache();
    cCache.Add(new Uri(jenkinsUrl), "Basic", new NetworkCredential(jenkinsName, jenkinsPwd));
    return (HttpWebRequest)WebRequestHelper.GetRequest(requestUrl, cCache);
    }

    private static string formatHtml(string responseHTML)
    {
    return responseHTML.Replace("\r\n", "").Replace("\n", "");
    }
    }

    public class WebRequestHelper
    {
    public static WebRequest GetRequest(Uri requestUrl, CredentialCache credential)
    {
    HttpWebRequest request = null;
    if (requestUrl != null)
    {
    try
    {
    request = HttpWebRequest.Create(requestUrl) as HttpWebRequest;
    if (credential != null)
    {
    request.Credentials = credential;
    NetworkCredential nCredential = CredentialCache.DefaultNetworkCredentials;
    request.Headers["Authorization"] = "Basic" + Convert.ToBase64String(Encoding.Default.GetBytes(nCredential.UserName + ":" + nCredential.Password));
    }
    }
    catch
    {
    throw;
    }
    }
    return request;
    }
    }
    }

    补充:

    JavaScriptSerializer序列化和反序列化JSON:使用自定义JavaScriptConverter
    JSON的序列化和反序列化已经成为Web开发必不可少的知识。现在常用的有System.Web.Script.Serialization下的JavaScriptSerializer来进行处理;另外一个比较常用且高效的类库是JSON.NET。
    
    在开发一些小的应用时,由于想尽量较少项目的依赖,所以不太愿意使用JSON.NET。JavaScriptSerializer基本上能满足简单的需求,但当一个属性要序列化成别的名字时,就显得力不从心了。还有就是可能业务需要,某些属性不希望在某一个条件下进行序列化。鉴于上面的业务需要,我们就需要自定义一个JavaScriptConverter。
    
    自定义JavaScriptConverter的使用流程:
    
    定义一个JavaScriptConverter,指明期支持的类型。
    在序列化方法调用前注册该转换器。
    显然,这两个步骤都不是很麻烦。我们举一个具体的业务环境来说明:在ExtJS的TreePanel控件中,TreeNode的属性有id、text等,其中如果checked属性存在,则属性结果显示节点选择框。在C#中,checked是关键字,所以不能定义为属性,TreeNode的C#代码如下:
    
    复制代码
        public class TreeNode
        {
            public string id { get; set; }
            public string text { get; set; }
            public bool? isChecked { get; set; }
            public List<TreeNode> children { get; set; }
        }
    复制代码
    我将checked属性映射到类中的isChecked字段,该字段可以有三个状态:null、true和false,当为null的时候,将不会序列化该字段,前台也不会显示节点选择框。
    
    现在要实现一个TreeNodeJSConverter,代码如下:
    
    复制代码
        public class TreeNodeJSConverter : JavaScriptConverter
        {
            public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
            {
                TreeNode node = new TreeNode();
    
                object value = null;
                if (dictionary.TryGetValue("id", out value))
                    node.id = (string)value;
                if (dictionary.TryGetValue("text", out value))
                    node.text = (string)value;
                if (dictionary.TryGetValue("children", out value))
                {
                    if (value != null && value.GetType() == typeof(ArrayList))
                    {
                        var list = (ArrayList)value;
                        node.children = new List<TreeNode>();
    
                        foreach (Dictionary<string, object> item in list)
                        {
                            node.children.Add((TreeNode)this.Deserialize(item, type, serializer));
                        }
                    }
                    else
                    {
                        node.children = null;
                    }
                }
                return node;
            }
    
            public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                var node = obj as TreeNode;
                if (node == null)
                    return null;
                if(!string.IsNullOrEmpty(node.id))
                dic.Add("id", node.id);
                if (!string.IsNullOrEmpty(node.text))
                dic.Add("text", node.text);
                if (node.isChecked.HasValue)
                    dic.Add("checked", node.isChecked.Value);
                if (node.children != null)
                dic.Add("children", node.children);
    
                return dic;
            }
    
            public override IEnumerable<Type> SupportedTypes
            {
                get
                {
                    return new Type[] { typeof(TreeNode) };
                }
            }
        }
    复制代码
    代码讨论:TreeNodeJSConverter类首先需要继承JavaScriptConverter,然后实现它的相关方法:Deserialize、Serialize和SupportedTypes,分别是反序列化、序列化和支持的类型。
    
    在序列化方法Serialize中,我们需要将属性添加到一个字典结构中,就可以完成序列化的工作了。具体要序列化那些字段还是要判断一下相应的值是否存在。
    
    在反序列化方法Deserialize中,字典结构存放着相应的值,当值存在的时候就可以为TreeNode相应的字段赋值。比较麻烦的事children属性,因为其为嵌套的List类型,而JSON中的数组结构会被转化成ArrayList结构,所以我们只需要递归的循环ArrayList中的每一个项,将其转换为TreeNode就可以了。
    
    最后是SupportedTypes字段,返回支持的类型,我们这里显示的返回TreeNode的类型。
    
     
    
    定义好了转换器之后,我们需要为在序列化的时候注册该转换器即可:
    
    复制代码
            public static string SerializeToJson(object obj)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                serializer.RegisterConverters(new JavaScriptConverter[] { new TreeNodeJSConverter() });
    
                return serializer.Serialize(obj);
            }
    
            public static T DeserializeJson<T>(string jsonString)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                serializer.RegisterConverters(new JavaScriptConverter[] { new TreeNodeJSConverter() });
    
                return serializer.Deserialize<T>(jsonString);
            }
    复制代码
    代码中标红的部分就是注册转化器的地方,用起来很方便,代码都贴出来了,不再提供源码下载了。。亲,早点睡吧!
    View Code

     折腾着一上午, 已经用掉很多时间了, 这里就草草标记一下, 不再整理了. 其中参考了3篇文章, 深受启发.

    我已经把三篇放一起了, 文章地址: http://www.cnblogs.com/cs_net/articles/2361181.html

    三篇原帖地址:

    http://heeroluo.net/ShowPost15.aspx

    http://www.cnblogs.com/Henllyee/archive/2008/07/18/1246161.html

    http://www.cnblogs.com/zhuisha/archive/2008/12/08/1350463.html

  • 相关阅读:
    用GDB调试程序(一)
    vim添加删除多行注释
    python binary lib on win/各种python库的二进制包
    python使用libssh2连接linux
    python xpath
    splinter python浏览器自动化操作,模拟浏览器的行为
    pytesser图片文本识别
    python验证码识别
    Python 之 使用 PIL 库做图像处理
    Connection reset by peer问题分析
  • 原文地址:https://www.cnblogs.com/cs_net/p/2361466.html
Copyright © 2011-2022 走看看