zoukankan      html  css  js  c++  java
  • 在ASP.NET中实现AJAX(二)

    (......接上)

    客户端调用

    最后一步是用JavaScript调用该函数。AJAX包装器负责创建带有两个参数的JavaScript 函数Sample.ServerSideAdd。对这种最简单的函数,只需要调用该方法并传递两个数字:

    <%@ Page Inherits="AjaxPlay.Sample" Codebehind="sample.aspx.cs" ... % >
    <html>
    <head>
    <script language="javascript" src="ajax/common.ashx"></script>
    <script language="javascript"
         
    src="ajax/AjaxPlay.Sample,AjaxPlay.ashx"></script>
    </head>
    <body>  

      
    <form id="Form1" method="post" runat="server">
       
    <script language="javascript">
        
    var response = Sample.ServerSideAdd (100,99);
        
    alert(response.value);
       
    </script>
       </form>  

    </body>
    </html>

    当然,我们不希望仅仅用这种强大的能力来警告用户。这就是所有客户端代理(如 JavaScript Sample.ServerSideAd函数)还接受其他特性的原因。这种特性就是为了处理响应而调用的回调函数:

    Sample.ServerSideAdd(100,99, ServerSideAdd_CallBack);

    function ServerSideAdd_CallBack(response){
    if (response.error != null){
    alert(response.error);
    return;
    }
    alert (response.value);
    }

    从上述代码中可以看到我们指定了另外一个参数。ServerSideAdd_CallBack(同样参见上述代码)是用于处理服务器响应的客户端函数。这个回调函数接收一个响应对象,该对象公开了三个主要性质

    • Value——服务器端函数实际返回的值(无论是字符串、自定义对象还是数据集)。
    • Error——错误消息,如果有的话。
    • Request——xml http请求的原始响应。
    • Context——上下文对象。

    首先我们检查error只看看是否出现了错误。通过在服务器端函数中抛出异常,可以很容易处理error特性。在这个简化的例子中,然后用这个值警告用户。Request特性可用于获得更多信息(参见下一节)。

    处理类型

    返回复杂类型

    Ajax包装器不仅能处理ServerSideAdd函数所返回的整数。它目前还支持integersstringsdoublebooleansDateTimeDataSetsDataTables,以及自定义类和数组等基本类型。其他所有类型都返回它们的ToString值。

    返回的DataSets和真正的.NET DataSet差不多。假设一个服务器端函数返回DataSet,我们可以通过下面的代码在客户端显示其中的内容:

    <script language="JavaScript">
    //Asynchronous call to the mythical "GetDataSet" server-side function
    function getDataSet(){
    AjaxFunctions.GetDataSet (GetDataSet_callback);  

    }
    function GetDataSet_callback(response) {
    var ds = response.value;
    if(ds != null && typeof(ds) == "object" && ds.Tables != null){
      
    var s = new Array();
      
    s[s.length] = "<table border=1>";
      
    for(var i=0; i<ds.Tables[0].Rows.length; i++){
       
    s[s.length] = "<tr>";
       
    s[s.length] = "<td>" + ds.Tables [0].Rows[i].FirstName + "</td>";
       
    s[s.length] = "<td>" + ds.Tables [0].Rows[i].Birthday + "</td>";
       
    s[s.length] = "</tr>";
      
    }
      
    s[s.length] = "</table>";
      
    tableDisplay.innerHTML = s.join ("");
    }
    else {
      
    alert("Error. [3001] " + response.request.responseText);
    }
    }
    </script>

    Ajax还可以返回自定义类,唯一的要求是必须用 Serializable属性标记。假设有如下的类:

    [Serializable()]
    public class User{
    private int _userId;
    private string _firstName;
    private string _lastName;

    public int userId{
      
    get { return _userId; }
    }
    public string FirstName {
      
    get { return _firstName; }
    }
    public string LastName{
      
    get { return _lastName; }
    }
    public User(int _userId, string _firstName, string _lastName){
      
    this._userId = _userId;
      
    this._firstName = _firstName;
      
    this._lastName = _lastName;
    }
    public User(){}
    [AjaxMethod()]
    public static User GetUser(int userId) {
      
    //Replace this with a DB hit or something :)
      
    return new User(userId,"Michael", "Schwarz");
    }
    }

    我们可以通过调用RegisterTypeForAjax注册GetUser代理:

    private void Page_Load(object sender, EventArgs e) {
    Utility.RegisterTypeForAjax(typeof(User));
    }

    这样就可以在客户端异步调用GetUser

    <script language="javascript">
    function getUser(userId) {
    User.GetUser(GetUser_callback);
    }
    function GetUser_callback(response) {
    if (response != null && response.value != null){
      
    var user = response.value;
       if (typeof(user) == "object") {     

       
    alert(user.FirstName + " " + user.LastName);
      
    }
    }
    }
    getUser(1);
    </script>

    响应中返回的值实际上是一个对象,公开了和服务器端对象相同的属性(FirstName、 LastName和UserId)。

    自定义转换器

    我们已经看到,Ajax .NET包装器能够处理很多不同的.NET类型。但是除了大量.NET类和内建类型以外,包装器对不能正确返回的其他类型仅仅调用ToString()。为了避免这种情况,Ajax .NET包装器允许开发人员创建对象转换器,用于在服务器和客户机之间平滑传递复杂对象。

    其他事项

    在其他类中注册函数

    上面的例子中,我们的服务器端函数都放在执行页面背后的代码中。但是,没有理由不能把这些函数放在单独的类文件中。要记住,包装器的工作方式是在指定类中发现所有带Ajax.AjaxMethod的方法。需要的类通过第二个脚本标签指定。使用Ajax.Utility.RegisterTypeForAjax,我们可以指定需要的任何类。比如,将我们的服务器端函数作为单独的类是合情合理的:

    Public Class AjaxFunctions
    <Ajax.AjaxMethod()> _
    Public Function Validate(username As String, password As String) As Boolean
      
    'do something
      
    'Return something
    End Function
    End Class

    通过指定类的类型而不是页面就可以让Ajax包装器创建代理:

    private void Page_Load(object sender, EventArgs e) {
    Ajax.Utility.RegisterTypeForAjax(typeof(AjaxFunctions));
    //...
    }

    要记住,客户端代理的名称是<ClassName>.<ServerSideFunctionName>。因此,如果ServerSideAdd函数放在上面虚构的AjaxFunctions类中,客户端调用就应该是: AjaxFunctions.ServerSideAdd(1,2)

    代理到底是如何工作的

    Ajax工具生成的第二个脚本标签(也可以手工插入)传递了页面的名称空间、类名和程序集。根据这些信息,Ajax.PageHandlerFactory就能够使用反射得到具有特定属性的任何函数的详细信息。显然,处理函数查找具有AjaxMethod属性的函数并得到它们的签名(返回类型、名称和参数),从能够创建必要的客户端代理。具体而言,包装器创建一个和类同名的JavaScript对象,该对象提供代理。换句话说,给定一个带有 Ajax ServerSideAdd方法的服务器端类AjaxFunctions,我们就会得到公开ServerSideAdd函数的AjaxFunction JavaScript对象。如果将浏览器指向第二个脚本标签的路径就会看到这种动作。

    返回Unicode字符

    Ajax .NET包装器能够从服务器向客户机返回 Unicode字符。为此,数据在返回之前必须在服务器上用html编码。比如:

    [Ajax.AjaxMethod]
    public string Test1(string name, string email, string comment){
    string html = "";
    html += "Hello " + name + "<br>";
    html += "Thank you for your comment <b>";
    html += System.Web.HttpUtility.HtmlEncode(comment);
    html += "</b>.";
    return html;
    }

    SessionState

    服务器端函数中很可能需要访问会话信息。为此,只需要通过传递给Ajax.AjaxMethod属性的一个参数告诉Ajax启用这种功能。

    在考察包装器会话能力的同时,我们来看看其他几个特性。这个例子中我们有一个文档管理系统,用户编辑的时候会对文档加锁。其他用户可以请求在文档可用的时候得到通知。如果没有AJAX,我们就只能等待该用户再次返回来检查请求的文档是否可用。显然不够理想。使用支持会话状态的Ajax就非常简单了。

    首先来编写服务器端函数,目标是循环遍历用户希望编辑的documentId(保存在会话中)并返回所有已释放的文档。

    [Ajax.AjaxMethod(HttpSessionStateRequirement.Read)]
    public ArrayList DocumentReleased(){
    if (HttpContext.Current.Session["DocumentsWaiting"] == null) {
      
    return null;
    }
    ArrayList readyDocuments = new ArrayList();
    int[] documents = (int[])HttpContext.Current.Session["DocumentsWaiting"];
    for (int i = 0; i < documents.Length; ++i){
      
    Document document = Document.GetDocumentById(documents[i]);
      
    if (document != null && document.Status == DocumentStatus.Ready){
       
    readyDocuments.Add (document);
       }    

    }
    return readyDocuments;
    }
    }

    要注意,我们指定了HttpSessionStateRequirement.Read值(还可以用WriteReadWrite)。

    现在编写使用该方法的JavaScript:

    <script language="javascript">
    function DocumentsReady_CallBack (response){
    if (response.error != null){
      
    alert(response.error);
      
    return;
    }
    if (response.value != null && response.value.length > 0){
      
    var div = document.getElementById ("status");
      
    div.innerHTML = "The following documents are ready!<br />";
      
    for (var i = 0; i < response.value.length; ++i) {
       
    div.innerHTML += "<a href=\"edit.aspx?documentId=" + response.value [i].DocumentId + "\">" + response.value[i].Name + "</a><br />";
       }    

    }
    setTimeout('page.DocumentReleased(DocumentsReady_CallBack)', 10000);
    }
    </script>

    <body onload="setTimeout('Document.DocumentReleased (DocumentsReady_CallBack)', 10000);">

    我们的服务器端函数在页面加载时调用一次,然后每隔10秒钟调用一次。回调函数检查响应看看是否有返回值,有的话则在div标签中显示该用户可使用的新文档。

    结束语

    AJAX技术已经催生了原来只有桌面开发才具备的健壮而丰富的Web界面。Ajax .NET包装器让您很容易就能利用这种新的强大技术。请注意,Ajax .NET包装器和文档仍在开发之中
  • 相关阅读:
    OleDbCommand 的用法
    递归求阶乘
    C#重写窗体的方法
    HDU 5229 ZCC loves strings 博弈
    HDU 5228 ZCC loves straight flush 暴力
    POJ 1330 Nearest Common Ancestors LCA
    HDU 5234 Happy birthday 01背包
    HDU 5233 Gunner II 离散化
    fast-IO
    HDU 5265 pog loves szh II 二分
  • 原文地址:https://www.cnblogs.com/chorrysky/p/1263825.html
Copyright © 2011-2022 走看看