首頁 web前端 js教程 編寫輕量ajax元件01-與webform平台上的各種實作方式比較

編寫輕量ajax元件01-與webform平台上的各種實作方式比較

May 24, 2018 pm 02:57 PM
ajax web

這篇文章主要介紹了寫輕量級ajax元件01-與webform平台上的各種實現方式比較,需要的朋友可以參考下

前言

  Asp.net WebForm 和Asp.net MVC(簡稱MVC) 都是基於Asp.net的web開發框架,兩者有很大的區別,其中一個就是MVC更加註重http本質,而WebForm試圖屏蔽http,為此提供了大量的伺服器控制項和ViewState機制,讓開發人員可以像開發Windows Form應用程式一樣,基於事件模型去程式設計。兩者各有優缺點和適用情景,但MVC現在是許多Asp.net開發者的首選。

  WebForm是建立在Asp.net的基礎上的,Asp.net提供了足夠的擴展性,我們也可以利用這些在WebForm下編寫像MVC一樣的框架,這個有機會再寫。說到WebForm很多人就會聯想到伺服器控件(拖曳控件!!!),其實不然,我們也可以完全不使用伺服器控件,像MVC一樣關注html。 WebForm要拋棄伺服器控件,集中在html,首先就要將

標籤去掉,這個runat server 的form 是其PostBack機制的基礎。既然我們要回歸到html css js,那麼意味著許多東西都要自己實現,例如處理Ajax請求。不像MVC那樣,WebForm開始的設計就將伺服器控制項當作主要組成部分,如果不使用它,那麼只能利用它的擴充性去實作。

  本系列就是實作一個基於WebForm平台的輕量ajax元件,主要分為三個部分:

  1. 介紹WebForm下各種實作方式。

  2. 分析ajaxpro組件。

  3. 寫出自己的ajax元件。

一、Ajax簡介

  非同步允許我們在不刷新整個頁面的情況下,像伺服器請求或提交資料。對於複雜的頁面,為了請求一點資料而重載整個頁面顯然是很低效的,ajax就是為了解決這個問題的。 ajax的核心是XmlHttpRequest對象,透過該對象,以文字的形式向伺服器提交請求。 XmlHttpRequest2.0後,也支援提交二進位資料。

  ajax安全:出於安全考慮,ajax受同源策略限制;也就是只能存取同一個域、同一個連接埠的請求,跨域請求會被拒絕。當然有時候需求需要跨域發送請求,常用的跨域處理方法有CORS(跨域資源共享)和JSONP(參數式JSON)。

  ajax資料互動格式:雖然Ajax核心物件XmlHttpRequest有"XML"字眼,但客戶端與伺服器資料交換格式不限於xml,例如現在更多是使用json格式。  

  ajax 也是有缺點的。例如對搜尋引擎的支援不太好;有時候也會違背url資源定位的初衷。

二、Asp.net MVC 平台下使用ajax

  在MVC裡,ajax呼叫後台方法非常方便,只需要指定Action的名稱即可。

  前台程式碼:

<body>
  <h1>index</h1>
  <input type="button" value="GetData" onclick="getData()" />
  <span id="result"></span>
</body>
<script type="text/javascript">
  function getData() {
    $.get("GetData", function (data) {
      $("#result").text(data);
    });
  }
</script>
登入後複製

#  後台程式碼:

##

public class AjaxController : Controller
{
  public ActionResult GetData()
  {
    if(Request.IsAjaxRequest())
    {
      return Content("data");
    }
    return View();
  }
}
登入後複製

#三、WebForm 平台下使用ajax

  

3.1 基於伺服器控制項套件或第三方元件

  這是基於伺服器控制項的,例如ajax toolkit工具包,或像FineUI這樣的元件。 web前端始終是由html css js組成的,只不過如何去產生的問題。原生的我們可以自己寫,或是用一些前端插件;基於伺服器控制項的,都是在後台產生的,通常效率也低一點。伺服器元件會在前台產生一系列代理,本質還是一樣的,只不過控制項封裝了這個過程,不需要我們自己寫。基於控制項或第三方元件的模式,在某些管理系統還挺有用的,訪問量不是很大,可以快速開發。

  

3.2 基於ICallbackEventHandler介面

  .net 提供了ICallbackEventHandler接口,用於處理回調請求。此介面需要用ClientScriptManager在前台產生代理腳本,用於傳送和接收請求,所以需要
標籤。

  前台程式碼:

<body>
  <form id="form1" runat="server">
  <p>    
    <input type="button" value="获取回调结果" onclick="callServer()" />
    <span id="result" style="color:Red;"></span>
  </p>
  </form>
</body>
<script type="text/javascript">
  function getCallbackResult(result){
    document.getElementById("result").innerHTML = result;
  }
</script>
登入後複製

#  後台程式碼:

##
public partial class Test1 : System.Web.UI.Page, ICallbackEventHandler
{    
  protected void Page_Load(object sender, EventArgs e)
  {
    //客户端脚本Manager
    ClientScriptManager scriptMgr = this.ClientScript;
 
    //获取回调函数,getCallbackResult就是回调函数
    string functionName = scriptMgr.GetCallbackEventReference(this, "", "getCallbackResult", "");
 
    //发起请求的脚本,callServer就是点击按钮事件的执行函数
    string scriptExecutor = "function callServer(){" + functionName + ";}";
 
    //注册脚本
    scriptMgr.RegisterClientScriptBlock(this.GetType(), "callServer", scriptExecutor, true);
  }
 
  //接口方法
  public string GetCallbackResult()
  {
    return "callback result";
  }
 
  //接口方法
  public void RaiseCallbackEvent(string eventArgument)
  {
  }
}
登入後複製

#這種方式有以下缺點

  1. 實作起來較複雜,每個頁面Load事件都要去註冊對應的腳本。

  2. 前台會產生一個用於代理程式的腳本檔案。

  3. 對於頁面互動複雜的,實現起來非常麻煩。

  4. 雖然是回調,但此時頁面物件還是生成了。

  3.3 使用一般處理程序

  一般处理程序其实是一个实现了IHttpHandler接口类,与页面类一样,它也可以用于处理请求。一般处理程序通常不用于生成html,也没有复杂的事件机制,只有一个ProcessRequest入口用于处理请求。我们可以将ajax请求地址写成.ashx文件的路径,这样就可以处理了,而且效率比较高。

  要输出文本内容只需要Response.Write(data)即可,例如,从数据库获取数据后,序列化为json格式字符串,然后输出。前面说到,一般处理程序不像页面一样原来生成html,如果要生成html,可以通过加载用户控件生成。如:

public void ProcessRequest(HttpContext context)
{
  Page page = new Page();
  Control control = page.LoadControl("~/PageOrAshx/UserInfo.ascx");
  if (control != null)
  {
    StringWriter sw = new StringWriter();
    HtmlTextWriter writer = new HtmlTextWriter(sw);
    control.RenderControl(writer);
    string html = sw.ToString();
    context.Response.Write(html);        
  }
}
登入後複製

  这种方式的优点是轻量、高效;缺点是对于交互多的需要定义许多ashx文件,加大了管理和维护成本。

  3.4 页面基类

  将处理ajax请求的方法定义在页面对象内,这样每个页面就可以专注处理本页面相关的请求了。这里有点需要注意。

  1.如何知道这个请求是ajax请求?

    通过请求X-Requested-With:XMLHttlRequest 可以判断,大部份浏览器的异步请求都会包含这个请求头;也可以通过自定义请求头实现,例如:AjaxFlag:XHR。

  2.在哪里统一处理?

    如果在每个页面类里判断和调用是很麻烦的,所以将这个处理过程转到一个页面基类里处理。

  3.如何知道调用的是哪个方法?

    通过传参或者定义在请求头都可以,例如:MethodName:GetData。

  4.知道方法名称了,如何动态调用?

    反射。

  5.如何知道该方法可以被外部调用?

    可以认为public类型的就可以被外部调用,也可以通过标记属性标记。

  通过上面的分析,简单实现如下  

  页面基类:

public class PageBase : Page
{
  public override void ProcessRequest(HttpContext context)
  {
    HttpRequest request = context.Request;
    if (string.Compare(request.Headers["AjaxFlag"],"AjaxFlag",0) == 0)
    {
      string methodName = request.Headers["MethodName"];
      if (string.IsNullOrEmpty(methodName))
      {
        EndRequest("MethodName标记不能为空!");
      }
      Type type = this.GetType().BaseType;
      MethodInfo info = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
      if (info == null)
      {
        EndRequest("找不到合适的方法调用!");
      }        
      string data = info.Invoke(this, null) as string;
      EndRequest(data);
    }
    base.ProcessRequest(context);
  }
  private void EndRequest(string msg)
  {
    HttpResponse response = this.Context.Response;
    response.Write(msg);
    response.End();
  }
}
登入後複製

  页面类:

public partial class Test1 : PageBase
{
  protected void Page_Load(object sender, EventArgs e)
  {
  }
  public string GetData()
  {
    return "213";
  }
}
登入後複製

  前台代码:

function getData(){
  $.ajax({
    headers:{"AjaxFlag":"XHR","MethodName":"GetData"},
    success:function(data){
      $("#result").text(data);
    }
  });
}
登入後複製

四、优化版页面基类

  上面的页面基类功能很少,而且通过反射这样调用的效率很低。这里优化一下:

  1.可以支持简单类型的参数。

    例如上面的GetData可以是:GetData(string name),通过函数元数据可以获取相关的参数,再根据请求的参数,就可以设置参数了。

  2.加入标记属性。

    只有被AjaxMethodAttribute标记的属性才能被外部调用。

  3.优化反射。

    利用缓存,避免每次都根据函数名称去搜索函数信息。

  标记属性:

public class AjaxMethodAttribute : Attribute
{
}
登入後複製


  缓存对象:  

public class CacheMethodInfo
{
  public string MethodName { get; set; }
  public MethodInfo MethodInfo { get; set; }
  public ParameterInfo[] Parameters { get; set; }
}
登入後複製


  基类代码:

public class PageBase : Page
{
  private static Hashtable _ajaxTable = Hashtable.Synchronized(new Hashtable());
  public override void ProcessRequest(HttpContext context)
  {      
    HttpRequest request = context.Request;
    if (string.Compare(request.Headers["AjaxFlag"],"XHR",true) == 0)
    {
      InvokeMethod(request.Headers["MethodName"]);
    }
    base.ProcessRequest(context);
  }
  /// <summary>
  /// 反射执行函数
  /// </summary>
  /// <param name="methodName"></param>
  private void InvokeMethod(string methodName)
  {
    if (string.IsNullOrEmpty(methodName))
    {
      EndRequest("MethodName标记不能为空!");
    }
    CacheMethodInfo targetInfo = TryGetMethodInfo(methodName);
    if (targetInfo == null)
    {
      EndRequest("找不到合适的方法调用!");
    }
    try
    {
      object[] parameters = GetParameters(targetInfo.Parameters);
      string data = targetInfo.MethodInfo.Invoke(this, parameters) as string;
      EndRequest(data);
    }
    catch (FormatException)
    {
      EndRequest("参数类型匹配发生错误!");
    }
    catch (InvalidCastException)
    {
      EndRequest("参数类型转换发生错误!");
    }
    catch (ThreadAbortException)
    {
    }
    catch (Exception e)
    {
      EndRequest(e.Message);
    }
  }
  /// <summary>
  /// 获取函数元数据并缓存
  /// </summary>
  /// <param name="methodName"></param>
  /// <returns></returns>
  private CacheMethodInfo TryGetMethodInfo(string methodName)
  {
    Type type = this.GetType().BaseType;
    string cacheKey = type.AssemblyQualifiedName;
    Dictionary<string, CacheMethodInfo> dic = _ajaxTable[cacheKey] as Dictionary<string, CacheMethodInfo>;
    if (dic == null)
    {
      dic = new Dictionary<string, CacheMethodInfo>();
      MethodInfo[] methodInfos = (from m in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
                    let ma = m.GetCustomAttributes(typeof(AjaxMethodAttribute), false)
                    where ma.Length > 0
                    select m).ToArray();
      foreach (var mi in methodInfos)
      {
        CacheMethodInfo cacheInfo = new CacheMethodInfo();
        cacheInfo.MethodName = mi.Name;
        cacheInfo.MethodInfo = mi;
        cacheInfo.Parameters = mi.GetParameters();
        dic.Add(mi.Name, cacheInfo);
      }
      _ajaxTable.Add(cacheKey, dic);
    }
    CacheMethodInfo targetInfo = null;
    dic.TryGetValue(methodName, out targetInfo);
    return targetInfo;
  }
  /// <summary>
  /// 获取函数参数
  /// </summary>
  /// <param name="parameterInfos"></param>
  /// <returns></returns>
  private object[] GetParameters(ParameterInfo[] parameterInfos)
  {
    if (parameterInfos == null || parameterInfos.Length <= 0)
    {
      return null;
    }
    HttpRequest request = this.Context.Request;
    NameValueCollection nvc = null;
    string requestType = request.RequestType;
    if (string.Compare("GET", requestType, true) == 0)
    {
      nvc = request.QueryString;
    }
    else
    {
      nvc = request.Form;
    }
    int length = parameterInfos.Length;
    object[] parameters = new object[length];
    if (nvc == null || nvc.Count <= 0)
    {
      return parameters;
    }
    for (int i = 0; i < length; i++)
    {
      ParameterInfo pi = parameterInfos[i];
      string[] values = nvc.GetValues(pi.Name);
      object value = null;
      if (values != null)
      {
        if (values.Length > 1)
        {
          value = String.Join(",", values);
        }
        else
        {
          value = values[0];
        }
      }
      if (value == null)
      {
        continue;
      }
      parameters[i] = Convert.ChangeType(value, pi.ParameterType);
    }      
    return parameters;
  }
  private void EndRequest(string msg)
  {
    HttpResponse response = this.Context.Response;
    response.Write(msg);
    response.End();
  }
}
登入後複製

  页面类:

public string GetData3(int i, double d, string str)
{
  string[] datas = new string[] { i.ToString(), d.ToString(), str };
  return "参数分别是:" + String.Join(",", datas);
}
登入後複製


  前台代码:

function getData3(){
  $.ajax({
    headers:{"AjaxFlag":"XHR","MethodName":"GetData3"},
    data:{"i":1,"d":"10.1a","str":"hehe"},
    success:function(data){
      $("#result").text(data);
    }
  });
}
登入後複製

五、总结

  上面的页面基类已经具备可以完成基本的功能,但它还不够好。主要有:

  1. 依附在页面基类。对于本来有页面基类的,无疑会变得更加复杂。我们希望把它独立开来,变成一个单独的组件。

  2. 效率问题。反射的效率是很低的,尤其在web这类应用程序上,更应该慎用。以动态执行函数为例,效率主要低在:a.根据字符串动态查找函数的过程。b.执行函数时,反射内部需要将参数打包成一个数组,再将参数解析到线程栈上;在调用前CLR还要检测参数的正确性,再判断有没有权限执行。上面的优化其实只优化了一半,也就是优化了查找的过程,而Invoke同样会有性能损失。当然,随着.net版本越高,反射的效率也会有所提升,但这种动态的东西,始终是用效率换取灵活性的。

  3.不能支持复杂参数。有时候参数比较多,函数参数一般会封装成一个对象类型。

  4. AjaxMethodAttribute只是一个空的标记属性。我们可以为它加入一些功能,例如,标记函数的名称、是否使用Session、缓存设置等都可以再这里完成。

  用过WebForm的朋友可能会提到AjaxPro组件,这是一个开源的组件,下一篇就通过源码了解这个组件,借鉴它的处理过程,并且分析它的优缺点。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

淺析json與jsonp區別及透過ajax取得json資料後格式的轉換

ajax非同步載入圖片實例分析

#Ajax發送和接收請求

#

以上是編寫輕量ajax元件01-與webform平台上的各種實作方式比較的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

解決jQuery AJAX請求遇到403錯誤的方法 解決jQuery AJAX請求遇到403錯誤的方法 Feb 20, 2024 am 10:07 AM

標題:解決jQueryAJAX請求出現403錯誤的方法及程式碼範例403錯誤是指伺服器禁止存取資源的請求,通常會導致出現這個錯誤的原因是請求缺少權限或被伺服器拒絕。在進行jQueryAJAX請求時,有時會遇到這種情況,本文將介紹如何解決這個問題,並提供程式碼範例。解決方法:檢查權限:首先要確保請求的URL位址是正確的,同時驗證是否有足夠的權限來存取該資

解決jQuery AJAX請求403錯誤的方法 解決jQuery AJAX請求403錯誤的方法 Feb 19, 2024 pm 05:55 PM

jQuery是一個受歡迎的JavaScript函式庫,用來簡化客戶端端的開發。而AJAX則是在不重新載入整個網頁的情況下,透過發送非同步請求和與伺服器互動的技術。然而在使用jQuery進行AJAX請求時,有時會遇到403錯誤。 403錯誤通常是伺服器禁止存取的錯誤,可能是由於安全性原則或權限問題導致的。在本文中,我們將討論如何解決jQueryAJAX請求遭遇403錯誤

如何使用Ajax從PHP方法取得變數? 如何使用Ajax從PHP方法取得變數? Mar 09, 2024 pm 05:36 PM

使用Ajax從PHP方法取得變數是Web開發中常見的場景,透過Ajax可以實作頁面無需刷新即可動態取得資料。在本文中,將介紹如何使用Ajax從PHP方法中取得變量,並提供具體的程式碼範例。首先,我們需要寫一個PHP檔案來處理Ajax請求,並傳回所需的變數。下面是一個簡單的PHP檔案getData.php的範例程式碼:

如何解決jQuery AJAX報錯403的問題? 如何解決jQuery AJAX報錯403的問題? Feb 23, 2024 pm 04:27 PM

如何解決jQueryAJAX報錯403的問題?在開發網頁應用程式時,經常會使用jQuery來發送非同步請求。然而,有時在使用jQueryAJAX時可能會遇到錯誤代碼403,表示伺服器禁止存取。這種情況通常是由伺服器端的安全性設定所導致的,但可以透過一些方法來解決這個問題。本文將介紹如何解決jQueryAJAX報錯403的問題,並提供具體的程式碼範例。一、使

如何從駕駛艙Web使用者介面啟用管理訪問 如何從駕駛艙Web使用者介面啟用管理訪問 Mar 20, 2024 pm 06:56 PM

Cockpit是一個面向Linux伺服器的基於Web的圖形介面。它主要是為了使新用戶/專家用戶更容易管理Linux伺服器。在本文中,我們將討論Cockpit存取模式以及如何從CockpitWebUI切換Cockpit的管理存取。內容主題:駕駛艙進入模式查找當前駕駛艙訪問模式從CockpitWebUI啟用Cockpit的管理訪問從CockpitWebUI禁用Cockpit的管理訪問結論駕駛艙進入模式駕駛艙有兩種訪問模式:受限訪問:這是駕駛艙的默認訪問模式。在這種存取模式下,您無法從駕駛艙Web用戶

PHP 與 Ajax:建立一個自動完成建議引擎 PHP 與 Ajax:建立一個自動完成建議引擎 Jun 02, 2024 pm 08:39 PM

使用PHP和Ajax建置自動完成建議引擎:伺服器端腳本:處理Ajax請求並傳回建議(autocomplete.php)。客戶端腳本:發送Ajax請求並顯示建議(autocomplete.js)。實戰案例:在HTML頁面中包含腳本並指定search-input元素識別碼。

PHP在Web開發中是屬於前端還是後端? PHP在Web開發中是屬於前端還是後端? Mar 24, 2024 pm 02:18 PM

PHP在Web開發中是屬於後端。 PHP是一種伺服器端腳本語言,主要用於處理伺服器端的邏輯,產生動態網頁內容。與前端技術相比,PHP更多地用於與資料庫互動、處理使用者請求以及生成頁面內容等後端操作。接下來透過具體的程式碼範例來說明PHP在後端開發中的應用。首先,我們來看一個簡單的PHP程式碼範例,用於連接資料庫並查詢資料:

PHP 與 Ajax:建立動態載入內容的解決方案 PHP 與 Ajax:建立動態載入內容的解決方案 Jun 06, 2024 pm 01:12 PM

Ajax(非同步JavaScript和XML)允許在不重新載入頁面情況下新增動態內容。使用PHP和Ajax,您可以動態載入產品清單:HTML建立一個帶有容器元素的頁面,Ajax請求載入資料後將資料加入到該元素中。 JavaScript使用Ajax透過XMLHttpRequest向伺服器傳送請求,從伺服器取得JSON格式的產品資料。 PHP使用MySQL從資料庫查詢產品數據,並將其編碼為JSON格式。 JavaScript解析JSON數據,並將其顯示在頁面容器中。點選按鈕觸發Ajax請求,載入產品清單。

See all articles