【问题标题】:Any way to do a synchronous PageMethods call?有什么方法可以进行同步 PageMethods 调用?
【发布时间】:2026-02-20 20:50:01
【问题描述】:

我正在尝试这样做:

function DelBatch()
{var userInfo = get_cookie("UserInfo");
PageMethods.DeleteBatchJSWM(userInfo, function(result)
                                          {window.location = "BatchOperations.aspx";});
}

但它仍然异步运行。我需要浏览器真正等到我的代码隐藏执行完毕,然后才能刷新它

有一个列表框加载了刚刚从数据库中删除的值,它们不应该是可见的。我遇到的问题是窗口位置在执行代码隐藏之前刷新,并且似乎没有任何内容被用户删除。

【问题讨论】:

    标签: javascript asp.net vb.net asynchronous pagemethods


    【解决方案1】:

    改为使用 jQuery ajax 调用它?它具有一个选项 (async),您可以在其中选择同步/异步模式:http://api.jquery.com/jQuery.ajax/

    这篇优秀的文章告诉你如何最好地从 jQuery 调用 PageMethods:http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/

    基本上,您需要做的就是:

    $.ajax({
      type: "POST",
      async: false,
      url: "yourpage.aspx/DeleteBatchJSWM",
      data: "{ put json representation of userInfo here }",
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      success: function(msg) {
        window.location = "BatchOperations.aspx";
      }
    });
    

    查看Crockford's JSON stringify 获取 json 格式化解决方案。

    【讨论】:

      【解决方案2】:

      如果您想避免使用 jQuery,一个变通方法是使用另一个 PageMethod,您可以在其中使用 javascript setInterval 函数检查操作的状态。它有点乱,但如果你想要零 jQuery,它就可以完成工作,它模仿你寻求的同步性。我将它用于大型操作,其中我想将进度条更新到客户端或其他东西。以下是根据您发布的代码如何执行此操作的示例:

      function DelBatch()
      {
      
              var userInfo = get_cookie("UserInfo");
              PageMethods.DeleteBatchJSWM(userInfo, function(result) {window.location = "BatchOperations.aspx";});
      
              var status;
      
          //Check to see if it has completed every second
              var myInterval = setInterval(function ()
              {
                  PageMethods.CheckDeleteBatchStatus(OnSuccess);
                      if (status == "Finished")
                      {
                          clearInterval(myInterval);
                              //Finished Deleting. Call your window refresh here
                      WindowRefresh(); 
                      }
              }, 1000);
      
      
              function OnSuccess(result)
              {
                  status = result;
              }
      }
      

      代码隐藏:

      [WebMethod]
      public static string CheckDeleteBatchStatus()
      {
          string status = GetDeleteBatchStatus(); //some function to get the status of your operation
          return status;
      }
      

      【讨论】:

        【解决方案3】:

        我偶然发现了这个网站:

        http://abhijit-j-shetty.blogspot.com/2011/04/aspnet-ajax-calling-pagemethods.html

        它有一个很好的方法来处理同步 PageMethod 调用。

        javascript代码如下:

        // Make sure page methods operate synchronously
        XMLHttpRequest.prototype.original_open = XMLHttpRequest.prototype.open;
            XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
        
            async = false;
        
            var eventArgs = Array.prototype.slice.call(arguments);
        
            var q = 0;
            return this.original_open.apply(this, eventArgs);
        }
        
        // Make a generic WebMethod caller:
        function WebMethodCall(FunctionName, callingobj) {
            var OnSuccess = function (result, userContext, methodName) {
                callingobj.push(result);
            }
        
            var OnFailure = function (error, userContext, methodName) {
                callingobj.push(error.get_message());
            }
        
            PageMethods[FunctionName](OnSuccess, OnFailure);
        
        }
        
        // OK, this is kludgy, but here goes. In order to have a synchronous PageMethod call
        // we need an object that persists in the namespace to stuff the result value into (like an array)
        // Essentially I'm emulating a ByRef call.
        
        // ThisResult is an empty list. The WebMethodCall function sticks a value into that list.
        // The code that makes the PageMethods get called synchronously is in Common.js
        
        // Use the functions
        var ThisResult = []; // This must be of a type which persists in the namespace
        WebMethodCall('HelloWorld', ThisResult);
        return ThisResult[0];
        

        【讨论】:

        • 我想到如果它能够处理 WebMethodCall 函数的任意参数会更好,但我还不知道该怎么做。
        【解决方案4】:

        Using jQuery 在 2009 年是 first recommended

        另一个(非常冗长)选项是实现一个同步 WebRequestExecutor,如 here (2007-07-04) 所示,并完善了 here (2007-10-30)。该技术的要点是将 ASP.NET AJAX Sys.Net.XMLHttpExecutor 复制为名为 Sys.Net.XMLHttpSyncExecutor 的新类,并将调用更改为 xmlHttpRequest.open 以将 false 作为最后一个参数传递以强制同步操作。

        可以使用WebRequestManager 将同步执行器插入到所有请求中,如下所示:

        Sys.Net.WebRequestManager.set_defaultExecutorType('Sys.Net.XMLHttpSyncExecutor');
        

        或者您可能希望根据请求切换它just before it is invoked

        Sys.Net.WebRequestManager.add_invokingRequest(function(sender, args) {
         if (iFeelLikeRunningThisRequestSynchronously) {
          args.get_webRequest().set_executor(new Sys.Net.XMLHttpSyncExecutor());
        }});
        

        This discussion 是这些链接中的大部分以及其他一些链接的来源。

        【讨论】:

          【解决方案5】:

          我写了这个,它可以让你同步调用一个 PageMethod。它也只会返回方法的结果,并抛出可以在 try/catch 块中捕获的错误,因此您无需担心提供 onSuccess 和 onError 函数。

          function synchronusPageMethod(method) {
          
              XMLHttpRequest.prototype.original_open = XMLHttpRequest.prototype.open;
          
              XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
                  async = false;
          
                  var eventArgs = Array.prototype.slice.call(arguments);
          
                  return this.original_open.apply(this, eventArgs);
              };
          
              var result;
              var error;
          
              var args = Array.prototype.slice.call(arguments).slice(1);
              args.push(function (res) {
                  result = res;
              });
          
              args.push(function (err) {
                  error = err;
              });
          
              method.apply(null, args);
          
              XMLHttpRequest.prototype.open = XMLHttpRequest.prototype.original_open;
          
              if (error !== undefined) {
                  throw error;
              } else {
                  return result;
              }
          }
          

          像这样使用它:

          try {
              var result = synchronusPageMethod(PageMethods.myMethod, argument0, argument1);
              console.log(result);
          } catch(error) {
              console.log(error);
          }
          

          【讨论】:

            最近更新 更多