Invoke PageMethods (ScriptManager) synchronously
בפוסט הזה התרעמתי על הצורה שמיקרוסופט מימשו את ה - PageMethods - כתבתי שהם כתבו harscode שכל הקריאות יהיו async.
כתוצאה מזה שאני חוקר כרגע את
IE8 חקרתי קצת את הנושא של
prototype ב - javascript מצאתי דרך לשנות ולהגדיר קריאות ב - PageMethods שיעכבו את המשך הריצה עד לקבלת תשובה.
לפני שאני אכתוב את הפיתרון נסתכל איך מיקרוסופט מימשו את ה - PageMethods. אם נחפור קצת בקובץ ה - javascript שמגיע עם ה - script manager נראה את הקוד הבא.
function Sys$Net$XMLHttpExecutor$executeRequest() {
// some code...
var verb = this._webRequest.get_httpVerb();
this._xmlHttpRequest.open(verb, this._webRequest.getResolvedUrl(), true);
// some code..
}
בכל פעם שנפעיל מתודה בעזרת ה - Script Manager נגיע למתודה הזאת שבו הם מפעילים את מתודת open שולחים האם זה GET או POST שולחים את הכתובת של המתודה ו - true כדי להגדיר שזה אסינכרוני.
כדי שנוכל להחליט האם אנחנו רוצים את ההפעלה בצורה סינכרונית (למשל ב - CustomValidator) נצטרך לכתוב את הקוד הבא.
XMLHttpRequest.prototype.base_open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
async = false;
var args = Array.prototype.slice.call(arguments);
return this.base_open.apply(this, args);
};
בהתחלה נשמור reference למתודה open של XMLHttpRequest בעזרת prorotype.
לאחר מכן נגדיר מימוש חדש למתודה open (כלומר בכל פעם שיפעילו את המתודה open יגיעו למימוש שלנו)
נוכל להגדיר שהפרמטר async יהיה true או false.
ונפעיל את המימוש הקודם של open.
כעת נוכל לכתוב custom validator ולממש אותו בעזרת PageMethods (ולא נצטרך להגיע ל - jQuery - כמו שכתבתי
כאן)
<asp:Button ID="Button1" runat="server" Text="Button" />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:CustomValidator
ValidateEmptyText="true"
ID="CustomValidator1"
ControlToValidate="TextBox1"
ClientValidationFunction="customValid"
runat="server"
ErrorMessage="CustomValidator">
</asp:CustomValidator>
function customValid(sender, args) {
PageMethods.IsOk(args.Value, function(res) {
args.IsValid = res;
});
}
//Server Code
[WebMethod]
public static bool IsOk(string str)
{
return str == "ok";
}