【IT168 技术文档】假如我有这样一个网页 PageMethodTest.aspx :
第一次GET回来的HTML是这样的,<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PageMethodTest.aspx.cs" Inherits="PageMethodTest" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
[System.Web.Services.WebMethod]
[Microsoft.Web.Script.Services.ScriptMethod]
public static string MyMethod(string param)
{
return "MyMethod Called with \n" + param;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Page Method Test</title>
<script type="text/javascript" language="javascript">
function DoPageMethodCall()
{
var testString = "Simple page method call."
PageMethods.MyMethod(testString,
OnPageMethodRequestComplete);
}
function OnPageMethodRequestComplete(result)
{
alert(result);
}</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"/>
<div>
<input type="button" value="click me" onclick="javascript:DoPageMethodCall();" />
</div>
</form>
</body>
</html>
其中的PageMethods对象是根据aspx页面里的WebMethod定义的(其中的[Microsoft.Web.Script.Services.ScriptMethod]属性是可有可无的),而且只有在页面上有ScriptManager控件的情形下才会产生。这是在ScriptManager的OnPreRender()中在非IsInAsyncPostBack情形下调用了RegisterServices(),然后在其中调用了HTTP/1.1 200 OK
Date: Fri, 27 Oct 2006 17:59:47 GMT
Server: Microsoft-IIS/6.0
MicrosoftOfficeWebServer: 5.0_Pub
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 3389<!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><title>
Page Method Test
</title>
<script type="text/javascript" language="javascript">
function DoPageMethodCall()
{
var testString = "Simple page method call."
PageMethods.MyMethod(testString,
OnPageMethodRequestComplete);
}
function OnPageMethodRequestComplete(result)
{
alert(result);
}</script>
</head>
<body>
<form name="form1" method="post" action="PageMethodTest.aspx" id="form1">
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTIxMDg1NDQ4NzFkZO18etLQxHPe5EOcHfbCilxyvvK4" />
</div><script type="text/javascript">
<!--
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
// -->
</script><script src="/AJAXTest/WebResource.axd?d=yfaFGMiP-ZZNMhbEnIESKQ2&t=632964241567772266" type="text/javascript"></script>
<script src="/AJAXTest/WebResource.axd?
d=xw8kmunciznKjIDYByGU8vpKv3z7J4Cqa8fETeAhDbSyfVerCh-Y6jdz7WW_NrWJqiRBtIv_BFWbALvLJ-5wOe5_ay51heTWAjBTyYN1L6tEDFyr83tdAK6GuxXQz3vayfMDDoTkzr7rbUJ7nsU7J
WX867B5Bn5lKialNBEu1bU1&t=632973652131120740" type="text/javascript"></script>
<script type="text/javascript">
<!--
Sys.Services.AuthenticationService._set_authenticated(true);
// -->
</script><script src="/AJAXTest/WebResource.axd?
d=xw8kmunciznKjIDYByGU8vpKv3z7J4Cqa8fETeAhDbSyfVerCh-Y6jdz7WW_NrWJqiRBtIv_BFWbALvLJ-5wOe5_ay51heTWAjBTyYN1L6tEDFyr83tdAK6GuxXQz3vajHmKyHc_CEozMg5uffTNH
8QnkBCz9pfXsKAHDEtetN81&t=632973652131120740" type="text/javascript"></script>
<script type="text/javascript">
<!--
var PageMethods = {
MyMethod:Sys.Net._WebMethod._createProxyMethod(this,"MyMethod", "ASP.pagemethodtest_aspx.MyMethod",false,"param"),_get_path: function() { return'/AJAXTest/PageMethodTest.aspx'; },
set_timeout: function(value) { this._timeout = value; },
get_timeout: function() { return this._timeout; },
set_defaultUserContext: function(value) { this._userContext = value; },
get_defaultUserContext: function() { return this._userContext; },
set_defaultSucceededCallback: function(value) { this._succeeded = value; },
get_defaultSucceededCallback: function() { return this._succeeded; },
set_defaultFailedCallback: function(value) { this._failed = value; },
get_defaultFailedCallback: function() { return this._failed; }
}
// -->
</script><script type="text/javascript">
Sys.WebForms.PageRequestManager._initialize('ScriptManager1', document.getElementById('form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls([], [], [], 90);
</script><div>
<input type="button" value="click me" onclick="javascript:DoPageMethodCall();" />
</div>
</form>
</body>
</html>
string text1 = PageClientProxyGenerator.GetClientProxyScript(this.Context, this.Page);其后的调用是,
PageClientProxyGenerator.GetClientProxyScrip()->GeneratePrototype()->GenerateWebMethodProxy()
WebServiceData.MethodDatas属性会调用EnsureMethods(),通过反射从当前类中获取所有标有[WebMethod]的方法,输出到客户端,奇怪的是,如果这个静态WebMethod是在后台代码中的,则类似的脚本不会被输出
问题出在EnsureMethods()这个方法的flags1设置上,因为最终页的类是从后台页类继承来的,如果WebMethod方法是静态的,需要设置BindingFlags.FlattenHierarchy
private void EnsureMethods()
{
if ((this._methods == null) && (this._typeData.Type != null))
{
lock (this)
{
Dictionary<string, WebServiceMethodData> dictionary1 = new Dictionary<string,WebServiceMethodData>(StringComparer.OrdinalIgnoreCase);
BindingFlags flags1 = BindingFlags.Public;
if (this._pageMethods)
{
flags1 |= BindingFlags.Static;
}
else
{
flags1 |= BindingFlags.Instance;
}
MethodInfo[] infoArray1 = this._typeData.Type.GetMethods(flags1);
foreach (MethodInfo info1 in infoArray1)
{
object[] objArray1 = info1.GetCustomAttributes(typeof(WebMethodAttribute), true);
if (objArray1.Length != 0)
{
ScriptMethodAttribute attribute1 = null;
object[] objArray2 = info1.GetCustomAttributes(typeof(ScriptMethodAttribute), true);
if (objArray2.Length > 0)
{
attribute1 = (ScriptMethodAttribute) objArray2[0];
}
WebServiceMethodData data1 = new WebServiceMethodData(this, info1, (WebMethodAttribute) objArray1[0], attribute1);
dictionary1[data1.MethodName] = data1;
}
}
this._methods = dictionary1;
}
}
}