可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to do this:
function DelBatch()
{var userInfo = get_cookie("UserInfo");
PageMethods.DeleteBatchJSWM(userInfo, function(result)
{window.location = "BatchOperations.aspx";});
}
But it still runs asynchronously. I need the browser to actually wait until my code-behind is finished executing, then it can be refreshed
There's a listbox loaded with values that were just deleted from the database, they shouldn't be visible. Problem I have is the window location refreshes before the code-behind is executed, and nothing seems like it was deleted to the user.
回答1:
Call it using jQuery ajax instead? It features an option (async
) where you can select sync/async mode: http://api.jquery.com/jQuery.ajax/
This excellent article tells you how best to call PageMethods from jQuery: http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/
Essentially, all you will need to do is this:
$.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";
}
});
Look at Crockford's JSON stringify for a json formatting solution.
回答2:
If you want to avoid using jQuery, a work around would be to use another PageMethod in which you check the status of the operation using the javascript setInterval
function. It is a little messy, but it does the job if you want zero jQuery and it mimics the synchronicity you seek. I use it for large operations in which I want to update a progress bar to the client or something. Here would be an example of how you would do this given what code you posted:
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;
}
}
Code Behind:
[WebMethod]
public static string CheckDeleteBatchStatus()
{
string status = GetDeleteBatchStatus(); //some function to get the status of your operation
return status;
}
回答3:
I came across this site:
http://abhijit-j-shetty.blogspot.com/2011/04/aspnet-ajax-calling-pagemethods.html
that had a great method for handling Synchronous PageMethod calls.
The javascript code is as follows:
// 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];
回答4:
Using jQuery was first recommended back in 2009.
Another (extremely verbose) option is implementing a synchronous WebRequestExecutor as shown here (2007-07-04), and perfected here (2007-10-30). The gist of the technique is to copy the ASP.NET AJAX Sys.Net.XMLHttpExecutor as a new class named Sys.Net.XMLHttpSyncExecutor and change the call to xmlHttpRequest.open
to pass false
as the last parameter to force synchronous operation.
The synchronous executor can be plugged into all requests using WebRequestManager like this:
Sys.Net.WebRequestManager.set_defaultExecutorType('Sys.Net.XMLHttpSyncExecutor');
or you may want to switch it up per-request 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 is the source for most of these links and a few more.
回答5:
I wrote this, that lets you call a PageMethod synchronously. It also will just return the result of the method, and throw an error that can be caught in a try/catch block, so you don't need to worry about supplying onSuccess and onError functions.
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;
}
}
Use it like this:
try {
var result = synchronusPageMethod(PageMethods.myMethod, argument0, argument1);
console.log(result);
} catch(error) {
console.log(error);
}