非同期コールバックによるリアルタイム株価の表示


株式やファンドサイトでも、株式の価格がリアルタイムで変化し、ページ全体がリフレッシュを感じず、株の価格が絶えず変化しているだけで、これはどのように実現されているのでしょうか.
1.カスタムユーザコントロールファイルCallbackを追加する.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Callback.ascx.cs" 
Inherits="ClientControl_Callback" %>
<script type="text/javascript" lang="javascript">
    function <%=this.ID%>_OnCallbackCompleteDefault(ret) {
    }
</script>
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ClientControl_Callback : System.Web.UI.UserControl, System.Web.UI.ICallbackEventHandler
{
    public class CallbackEventArgs
    {
        public CallbackEventArgs()
        {
        }

        public CallbackEventArgs(string Parameter, string Result)
        {
            parameter = Parameter;
            result = Result;
        }

        private string parameter = "";
        public string Parameter
        {
            get { return parameter; }
            set { parameter = value; }
        } 

        private string result = "";
        public string Result
        {
            get { return result; }
            set { result = value; }
        }
    }

    public delegate void CallbackEventHandler(object source, CallbackEventArgs e);
    public event CallbackEventHandler Callback;
    private CallbackEventArgs EventArgs;

    #region   

    public string ClientPerformCallback
    {
        get
        {
            if (this.ViewState["ClientPerformCallback"] != null)
                return (string)this.ViewState["ClientPerformCallback"];
            return string.Empty;
        }
        set
        {
            this.ViewState["ClientPerformCallback"] = value;
        }
    } 

    public string ClientCompleteEvent
    {
        get
        {
            if (this.ViewState["ClientCompleteEvent"] != null)
                return (string)this.ViewState["ClientCompleteEvent"];
            return string.Empty;
        }
        set
        {
            this.ViewState["ClientCompleteEvent"] = value;
        }
    }

    public string ClientErrorEvent
    {
        get
        {
            if (this.ViewState["ClientErrorEvent"] != null)
                return (string)this.ViewState["ClientErrorEvent"];
            return string.Empty;
        }
        set
        {
            this.ViewState["ClientErrorEvent"] = value;
        }
    }

    #endregion
   
    protected void Page_Load(object sender, EventArgs e)
    {
        Callback += new CallbackEventHandler(OnCallback);

        string cbReference = "";
        string completeEvent = ClientCompleteEvent;

        if (string.IsNullOrEmpty(ClientCompleteEvent))
        {
            completeEvent = this.ID + "_OnCallbackCompleteDefault";
        }
        if (string.IsNullOrEmpty(ClientErrorEvent))
        {
            cbReference = Page.ClientScript.GetCallbackEventReference(
                this, "arg", completeEvent, "context", true);
        }
        else
        {
            cbReference = Page.ClientScript.GetCallbackEventReference(
                this, "arg", completeEvent, "context", ClientErrorEvent, true);
        } 

        string callbackScript = "function " + ClientPerformCallback + "(arg, context)" 
                                + "{ " + cbReference + "} ;";
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), this.ID + "_CallBackJS_" 
              + ClientPerformCallback, callbackScript, true);
    }

    protected virtual void OnCallback(object source, CallbackEventArgs e)
    {
    }

    string ICallbackEventHandler.GetCallbackResult()
    {
        return EventArgs.Result;
    }

    void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
    {
        EventArgs = new CallbackEventArgs(eventArgument, "");
        Callback(this, EventArgs);
    }
}

2、このカスタムユーザーコントロールを使ってローカルリフレッシュの効果を実現する
新しいTestを作成します.aspxページ
<%@ Page Title="" Language="C#"  AutoEventWireup="true" CodeFile="Test.aspx.cs"%>
<%@ Register TagPrefix="cb" TagName="Callback" Src="~/Callback.ascx" %>
<script type="text/javascript" src="~/json2.js"></script>
<script type="text/javascript" language="javascript">
        $(function () {
            performCallback1();
            setInterval("performCallback1();", 10 * 1000);
           
        }); 

        function onCallbackComplete1(ret) {
            var mytable= document.getElementById("table1");;
            $("#table1").empty();
            if (ret == '' || ret == '[]') {
                return;
            } else {
                var stocks = JSON.parse(ret);
                for (var i = 0; i < stocks.length; i++) {
                    var row = mytable.insertRow(i);
                    var cell = row.insertCell(0);
                    cell.setAttribute("id", "tb_" + i + "_0");
                    $("#tb_" + i + "_0").text(stocks[i].Name);
                     cell = row.insertCell(1);
                    cell.setAttribute("id", "tb_" + i + "_1");
                    $("#tb_" + i + "_1").text(stocks[i].Price);
                }
            }
        }
 </script>

<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" runat="Server">
    <table id="table1">
       
    </table>
    <cb:Callback ID="Callback1" runat="server" OnCallback="Callback1_Callback"
       ClientCompleteEvent="onCallbackComplete1" ClientPerformCallback="performCallback1"/>
</asp:Content>

バックグラウンドコード:
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data;
using System.Text;

using Newtonsoft.Json;

public partial class Test : BasePage
{


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
        }
    }
    protected void Callback1_Callback(object source, UserControl_Callback.CallbackEventArgs e)
    {
        List<Stock> stockList = new List<Stock>();
        Random rdm =new Random();
        Stock stock = new Stock();
        stock.Name = "    ";
        stock.Price = rdm.Next(10);
        stockList.Add(stock);
        stock = new Stock();
        stock.Name = "    ";
        stock.Price = rdm.Next(10);
        stockList.Add(stock);
        e.Result = JavaScriptConvert.SerializeObject(stockList); ;
    }
}

 public class Stock
{
    private string _Name;
    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }

    private float _Price;
    public float Price
    {
        get { return _Price; }
        set { _Price = value; }
    }
}