ASP.NET本质论
上QQ阅读APP看书,第一时间看更新

3.2.4 使用一般处理程序生成JSON

在AJAX程序中,经常需要向浏览器返回JSON格式http://www.json.org/json-zh.html的数据结果,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它是基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。详细的JSON 规范可以参考 http://www.json.org/json-zh.html。

在第2章中,我们已经实现了自定义的上传管理,甚至已经在上下文对象中保存了上传进度的信息。通过JSON,我们可以向客户端返回服务器端的上传进度。

对于服务器端来说,所谓的JSON实际上就是一段字符,我们可以直接通过拼接字符串的形式来生成。需要注意的是,JSON中通过{ }来表示对象,这两个符号与c#字符格式化串中使用的展位符号{ }冲突,为了在格式化串中使用{ },可以将符号重复一次即可。例如,当需要输出一个{的时候,在C#的字符串中需要连续写两个{{。

为了防止浏览器缓冲服务器返回的内容,通过回应头禁止客户端的缓存,代码如下所示:

context.Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);

其他代码如代码清单3-2所示。

代码清单3-2 一般处理程序JSON

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DiskFileUpload
{
    public class UploadPercnetHandler: System.Web.IHttpHandler
    {
        #region IHttpHandler Members
        public bool IsReusable
        {
            get { return true; }
        }
        public void ProcessRequest(System.Web.HttpContext context)
        {
            string key = context.Request[DiskFileUpload.UploadFiles.
                DiskFileUpload_GUID];
            DiskFileUpload.UploadFiles item
                = context.Application[key] as DiskFileUpload.UploadFiles;
            int uploadPercent = 0;
            if (item != null)
            {
                uploadPercent = item.CompletePercent;
            }
            string json = string.Format(
                    "{{ \"percent\":{0} }}", uploadPercent
              );
context.Response.Cache.SetCacheability(System.Web.HttpCacheability.
              NoCache);
            context.Response.ContentType = "application/json";
            context.Response.Write(json);
        }
        #endregion
    }
  }

配合JavaScript脚本,可以实现上传过程中的动态显示。

<script type = "text/javascript">
function uploadProgress() {
    var elemBar = document.getElementById("barCell");
    var elemPercent = document.getElementById("percentCell");
    var uploadid = document.getElementById("DiskFileUpload_GUID").value;
    alert(uploadid);
    var timerid = window.setInterval(
        function() {
            var xhr;
            if (window.ActiveXObject)
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            else
                xhr = new XMLHttpRequest();
            xhr.open("get","progress.ashx?DiskFileUpload_GUID=" + uploadid,
                false);
            xhr.send(null);
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    var result = eval("(" + xhr.responseText + ")");
                    elemBar.style.width =result.percent + "%";
                    elemPercent.innerHTML = result.percent + "%"
                }
            }
        }
        , 1000
        );
}
 </script>

当用户单击上传按钮之后,启动上传进度的处理函数,显示当前的上传进度。

<asp:Button ID="Button1"runat="server"Text="Button"
            onclick="Button1_Click"
            OnClientClick="uploadProgress();"
            />

实际上传的效果如图3-2所示。

图3-2 显示上传进度

在.NET 3.5之后,定义在命名空间System.Runtime.Serialization.Json中的DataContractJsonSerializer可以帮助我们直接将一个对象格式化成JSON,或者将一个JSON反序列化为一个.NET中的对象实例。这样,实现起来可以更加简单,参见代码清单3-3。

代码清单3-3 .NET 3.5之后的实现

using System;
using System.Web;
public class Result
{
    public int percent { get; set; }
}
public class JsonHandler: IHttpHandler {
    public void ProcessRequest(HttpContext context) {
        context.Response.ContentType = "application/json";
        context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        System.Type type = typeof(Result);
        System.Runtime.Serialization.Json.DataContractJsonSerializer serializer
            = new System.Runtime.Serialization.Json.DataContractJsonSerializer(type);
        Result result = new Result();
        result.percent = 80;
        serializer.WriteObject(context.Response.OutputStream, result);
    }
    public bool IsReusable {
        get {
            return false;
        }
    }
}