.NET中回调事件的简单分析
在.NET的ASPX页面中,通过实现ICallbackEventHandler接口,可以实现与前台的JavaScript进行交互,同时页面也不会进行刷新操作。可以肯定的是通过Ajax实现的。但是怎么样验证我的想法呢。今天将生成的页面源代码分析了一下,看出了实现的过程了。
首先,按照通常的实现方式,下面以一个验证用户名的例子来做一个分析。例子的过程是如果填写的用户名是juelance,那么就代表用户名已经被占用了。
前台的代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript">
function result(val) {
alert(val);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<input id="Text1" type="text" />
<input id="Button1" type="button" value="检查是否被占用" onclick="CheckUserName()" />
</div>
</form>
</body>
</html>
后台代码:
string _arg = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
string callbackfunc = ClientScript.GetCallbackEventReference(this, "val", "result", null);
string raisefunc = "<script type='text/javascript'>\nfunction CheckUserName(){ \nvar username=document.getElementById('Text1'); \nvar val=username.value;\n" + callbackfunc + " \n}\n</script>";
ClientScript.RegisterClientScriptBlock(this.GetType(), "CheckUserName", raisefunc);
}
public string GetCallbackResult()
{
return _arg;
}
public void RaiseCallbackEvent(string eventArgument)
{
if (eventArgument.ToLower() == "juelance")
{
_arg = "已经占用";
}
else
{
_arg = "可以使用";
}
}
通过浏览此页面,查看页面源文件,找出关键的五处代码:
第一段<script type="text/javascript"> function result(val) { alert(val); } </script>
第二段<script type='text/javascript'> function CheckUserName(){ var username=document.getElementById('Text1'); var val=username.value; WebForm_DoCallback('__Page',val,result,null,null,false) } </script>
第三段<div> <input id="Text1" type="text" /> <input id="Button1" type="button" value="检查是否被占用" onclick="CheckUserName()" /> </div>
第四段<script type="text/javascript"> //<![CDATA[ WebForm_InitCallback();//]]> </script>
第五段<script src="/fileupload/WebResource.axd?d=9Tb_MUlmMDCcCyQuK_rG4FhymHvBLwJp4n0GFDh7eDHQ-LQWHqbCW2mQbjFZuz21VVpqY7H9UUGQdR-NlAisCjFvrHQ1&t=634209066757546466" type="text/javascript"></script>
关键是第二段中WebForm_DoCallback方法,这个js方法是从那里来的呢?浏览最后一段js指向的src,来看看,在文件中查找这个方法,可以看到定义如下:
function WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) {
var postData = __theFormPostData +
"__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) +
"&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument);
if (theForm["__EVENTVALIDATION"]) {
postData += "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value);
}
var xmlRequest,e;
try {
xmlRequest = new XMLHttpRequest();
}
catch(e) {
try {
xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e) {
}
}
var setRequestHeaderMethodExists = true;
try {
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader);
}
catch(e) {}
var callback = new Object();
callback.eventCallback = eventCallback;
callback.context = context;
callback.errorCallback = errorCallback;
callback.async = useAsync;
var callbackIndex = WebForm_FillFirstAvailableSlot(__pendingCallbacks, callback);
if (!useAsync) {
if (__synchronousCallBackIndex != -1) {
__pendingCallbacks[__synchronousCallBackIndex] = null;
}
__synchronousCallBackIndex = callbackIndex;
}
if (setRequestHeaderMethodExists) {
xmlRequest.onreadystatechange = WebForm_CallbackComplete;
callback.xmlRequest = xmlRequest;
xmlRequest.open("POST", theForm.action, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
xmlRequest.send(postData);
return;
}
callback.xmlRequest = new Object();
var callbackFrameID = "__CALLBACKFRAME" + callbackIndex;
var xmlRequestFrame = document.frames[callbackFrameID];
if (!xmlRequestFrame) {
xmlRequestFrame = document.createElement("IFRAME");
xmlRequestFrame.width = "1";
xmlRequestFrame.height = "1";
xmlRequestFrame.frameBorder = "0";
xmlRequestFrame.id = callbackFrameID;
xmlRequestFrame.name = callbackFrameID;
xmlRequestFrame.style.position = "absolute";
xmlRequestFrame.style.top = "-100px"
xmlRequestFrame.style.left = "-100px";
try {
if (callBackFrameUrl) {
xmlRequestFrame.src = callBackFrameUrl;
}
}
catch(e) {}
document.body.appendChild(xmlRequestFrame);
}
var interval = window.setInterval(function() {
xmlRequestFrame = document.frames[callbackFrameID];
if (xmlRequestFrame && xmlRequestFrame.document) {
window.clearInterval(interval);
xmlRequestFrame.document.write("");
xmlRequestFrame.document.close();
xmlRequestFrame.document.write('<html><body><form method="post"><input type="hidden" name="__CALLBACKLOADSCRIPT" value="t"></form></body></html>');
xmlRequestFrame.document.close();
xmlRequestFrame.document.forms[0].action = theForm.action;
var count = __theFormPostCollection.length;
var element;
for (var i = 0; i < count; i++) {
element = __theFormPostCollection[i];
if (element) {
var fieldElement = xmlRequestFrame.document.createElement("INPUT");
fieldElement.type = "hidden";
fieldElement.name = element.name;
fieldElement.value = element.value;
xmlRequestFrame.document.forms[0].appendChild(fieldElement);
}
}
var callbackIdFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackIdFieldElement.type = "hidden";
callbackIdFieldElement.name = "__CALLBACKID";
callbackIdFieldElement.value = eventTarget;
xmlRequestFrame.document.forms[0].appendChild(callbackIdFieldElement);
var callbackParamFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackParamFieldElement.type = "hidden";
callbackParamFieldElement.name = "__CALLBACKPARAM";
callbackParamFieldElement.value = eventArgument;
xmlRequestFrame.document.forms[0].appendChild(callbackParamFieldElement);
if (theForm["__EVENTVALIDATION"]) {
var callbackValidationFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackValidationFieldElement.type = "hidden";
callbackValidationFieldElement.name = "__EVENTVALIDATION";
callbackValidationFieldElement.value = theForm["__EVENTVALIDATION"].value;
xmlRequestFrame.document.forms[0].appendChild(callbackValidationFieldElement);
}
var callbackIndexFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackIndexFieldElement.type = "hidden";
callbackIndexFieldElement.name = "__CALLBACKINDEX";
callbackIndexFieldElement.value = callbackIndex;
xmlRequestFrame.document.forms[0].appendChild(callbackIndexFieldElement);
xmlRequestFrame.document.forms[0].submit();
}
}, 10);
}
在这段代码中与我需求相关的代码:
var postData = __theFormPostData +
"__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) +
"&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument);
if (theForm["__EVENTVALIDATION"]) {
postData += "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value);
}
var xmlRequest,e;
try {
xmlRequest = new XMLHttpRequest();
}
catch(e) {
try {
xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e) {
}
}
var setRequestHeaderMethodExists = true;
try {
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader);
}
catch(e) {}
var callback = new Object();
callback.eventCallback = eventCallback;
callback.context = context;
callback.errorCallback = errorCallback;
callback.async = useAsync;
var callbackIndex = WebForm_FillFirstAvailableSlot(__pendingCallbacks, callback);
if (!useAsync) {
if (__synchronousCallBackIndex != -1) {
__pendingCallbacks[__synchronousCallBackIndex] = null;
}
__synchronousCallBackIndex = callbackIndex;
}
if (setRequestHeaderMethodExists) {
xmlRequest.onreadystatechange = WebForm_CallbackComplete;
callback.xmlRequest = xmlRequest;
xmlRequest.open("POST", theForm.action, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
xmlRequest.send(postData);
return;
}
大致的原理是:通过一个Ajax请求,将客户端的方法发送到服务器,服务器执行完相关的方法后,再调用客户端的result方法,并将服务器中产生的结果传入,最后执行客户端的JavaScript方法。这样就完成了整个回调事件的过程。