Ajax и Сlient-Сallbacks в ASP.NET 2.0

Источник: Kigorw's Blog

Привет smile.gif
Хочу открыть свой блог, интересной, новой и в тоже время впечатляющей темой.
Итак вкратце, что же такое Ajax? - новая технология имя которой связывают с проектами гугла(Gmail тому хороший пример). Суть и преимущество - это посылка асинхронный запросов на сервер без постбеков!!! Т.е. наши веб приложения имеют отличнейший шанс стать быстрее, экономнее(в смысле трафика).
Пока вижу одни преемущества, разве что кроме большего кол-ва клиентского кода(JScript).
Но и этот вопрос можно решить если придерживаться методики ТDD. Покопался я немного в сети и нашел unit testing framework -http://www.edwardh.com/jsunit/ . Но сейчас не об этом.
Итак открываем VS.NET 2005 (завидуйте люди у которых её еще нет :-))
Создаем страничку такого содержания
<!--c1-->
CODE
<!--ec1-->
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
<script type ="text/javascript" language="jscript">
            var obj;
              function getXMLHTTPRequest()
              {
                 var xRequest=null;
                if (window.XMLHttpRequest) {
                xRequest=new XMLHttpRequest();
                }else if (typeof ActiveXObject != "undefined"){
                  xRequest=new ActiveXObject("Microsoft.XMLHTTP");
                }
                  return xRequest;
                }
            function GetDataViaAJAX()
            {
                obj=getXMLHTTPRequest();
                if(obj!=null)
                {
                    obj.onreadystatechange = ProcessResponse;
                    obj.open("GET", "http://localhost:1392/Ajax1/ProcessedPage.aspx",  true);//урла страницы респонс которой будем читать
                    obj.send(null);        
                }
                return false;
            }

            function ProcessResponse()
            {
                if(obj.readyState == 4)
                {
                    if(obj.status == 200)
                    {
                        var retval=obj.responseText;  
                        if (document.getElementById("Label1")!=null)
                        document.getElementById("Label1").innerHTML=retval;
                    }
                    else
                    {
                        alert("Error retrieving data!" );
                    }  
                }
            }
</script>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server"  Text="Button" />
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label></div>
    </form>
</body>
</html>
<!--c2-->
<!--ec2-->
Небольшие пояснения:
function getXMLHTTPRequest() - возвращает объект, который отвечает за
асинхронную передачу данных, собственно в этом классе и заключается прелесть Аякса.
obj.onreadystatechange = ProcessResponse; - функция ProcessResponse обрабатывает ответ сервера, т.е является обработчиком события onreadystatechange.
(obj.readyState == 4) - 4 означает что запрос завершен
if(obj.status == 200) - 200 говорит что успешно
На сервере такой код:
<!--c1-->
CODE
<!--ec1-->
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Button1.Attributes.Add("OnClick", "return GetDataViaAJAX();");
        if (Page.IsPostBack)    Label1.Text = "Server Date Time :" + DateTime.Now;
      
    }

}
<!--c2-->
<!--ec2-->

Страница ProcessedPage.aspx
<!--c1-->
CODE
<!--ec1-->
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class ProcessedPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Clear();
        Response.Write("Hi from ProcessedPage");
        Response.End();
    }
}
<!--c2-->
<!--ec2-->
Вот, думаю с серверным кодом все понятно)

Далее рассмотрим альтернативный подход предложенный во 2ой версии асп.нет.
Создаем страничку с таким содержанием:
<!--c1-->
CODE
<!--ec1-->
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Callbacks.aspx.cs" Inherits="Callbacks" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Untitled Page</title>
    <script type="text/javascript">
        function SendCustomerName()  // отправляем значение комбобокса на сервер(эту функцию сгенерим в серверном коде)
        {
            var name=document.getElementById("DropDownList1").value;
            CallServer(name,"This is context from client");
            return false;
        }
        
        function ReceiveServerData(args, context) // получаем с сервера значение и показываем в лист боксе
        {
              
            var ddlPhones = document.getElementById("ListBox1");
            for (var count = ddlPhones.options.length-1; count >-1; count--) //чистим лист бокс
            {
                ddlPhones.options[count] = null;
            }
            
            var text;
            var listItem;
                text = args;
                listItem = new Option(text, text,  false, false);
                ddlPhones.options[ddlPhones.length] = listItem;    // добавляем аргумент полученный с сервера        
            
            
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:DropDownList id="DropDownList1" style="Z-INDEX: 101; LEFT: 152px; POSITION: absolute; TOP: 80px"
                runat="server" Width="160px"></asp:DropDownList>
        &nbsp;
            <asp:Label id="Label1" style="Z-INDEX: 102; LEFT: 152px; POSITION: absolute; TOP: 48px" runat="server">Customers :</asp:Label>
            <asp:Label id="Label2" style="Z-INDEX: 103; LEFT: 152px; POSITION: absolute; TOP: 112px" runat="server">Phone :</asp:Label>
            <asp:ListBox id="ListBox1" style="Z-INDEX: 104; LEFT: 152px; POSITION: absolute; TOP: 136px"
                runat="server" Width="160px" Height="112px"></asp:ListBox>
        &nbsp;
    </form>
</body>
</html>
<!--c2-->
<!--ec2-->
в этом случае интереснее то что у нас в серверном коде :-)
<!--c1-->
CODE
<!--ec1-->
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public sealed class Customer
{

    private string _Name;

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

    public string Phone
    {
        get { return _Phone; }
        set { _Phone = value; }
    }
    public Customer(string name, string phone)
    {
        this.Phone = phone;
        this.Name = name;
    }
}

public partial class Callbacks : System.Web.UI.Page,ICallbackEventHandler
{
    string str;
    ArrayList ds = new ArrayList();

    protected void Page_Load(object sender, EventArgs e)
    {
        FiilDataSource();
        if (!IsPostBack)
        {
            RegisterClientCallbackScript();
            FillDropDownList();
        }
    }

    private void RegisterClientCallbackScript()
    {
        ClientScriptManager m = Page.ClientScript;
        string cbReference = m.GetCallbackEventReference(this, "args", "ReceiveServerData", "'this is context from server'");
        string strCallback = "function CallServer(args,context){" + cbReference + ";}";
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", strCallback, true);
    }

    private void FillDropDownList()
    {
        DropDownList1.Attributes.Add("onchange", "return SendCustomerName();");
        DropDownList1.DataSource = ds;
        DropDownList1.DataTextField = "Name";
        DropDownList1.DataValueField = "Name";
        DropDownList1.DataBind();
    }

    private void FiilDataSource()
    {
        ds.Add(new Customer("Igor", "389734895-334458"));
        ds.Add(new Customer("Vasa", "389734895-44458"));
        ds.Add(new Customer("John", "389734895-3483234958"));
    }

    public string GetCallbackResult()
    {
        return str;

    }

    public void RaiseCallbackEvent(string eventArgument)
    {
        str = GetPhoneByName(eventArgument);
    }
    private string GetPhoneByName(string name)
    {
        string result = "";
        foreach (Object o in ds)
        {
            if ((o as Customer).Name == name) result = (o as Customer).Phone;
        }
        return result;
    }


}
<!--c2-->
<!--ec2-->
Итак пояснения:
RegisterClientCallbackScript() - добавляем клиентский код обеспечивающий механизм колбеков
<!--c1-->
CODE
<!--ec1-->
    public string GetCallbackResult()
    {
        return str;

    }

    public void RaiseCallbackEvent(string eventArgument)
    {
        str = GetPhoneByName(eventArgument);
    }
<!--c2-->
<!--ec2-->
Реализация интерфейса ICallbackEventHandler(ух я помучился читая в мсдн примеры несоответствующие действительной сигнатуре методов этого интерфейса)
Остальные методы служат для наполнения комбобокса тестовыми данными.
А да, скажу вообщем что делает этот код, когда мы выбираем в выпад. списке имя клиента, в листбоксе отображается его телефон и абсолютно без постбеков!!! Все ликуют и пьют шампанское smile.gif
Я б добавил проект того что в этом посте описано да видимо блог не позволяет этого sad.gif.

пс Сразу предупреждаю что я только начал изучать эту технологию, поэтому пинайте, но не сильно)


Опубликовал admin
29 Ноя, Вторник 2005г.



Программирование для чайников.