最近被問及Page Method的問題比較多,主要還是如何從Atlas CTP中的非靜態Page Method轉向Beta或RC中的靜態Page Method時所遇到的問題。現在我來談一下在這方面的一些看法,也希望大家能和我一起探討一下。
在當時,只要在Code Behind的Page類中添加一個實例方法,並且使用WebMethodAttribute進行標記即能使用,例如:
[WebMethod]
public string GetString(string split)
{
return this.TextBox1.Text + split + this.TextBox2.Text;
}
可以看到上面的方法能夠通過this引用訪問到頁面中的控件,然後取它們的值。如果要在客戶端調用的話,只要在頁面中編寫JavaScript代碼即可,如下:
function successCallback(result)
{
...
}
PageMethods.GetString('|', successCallback);
然而在Beta和RC的ASP.NET AJAX中則移除了實例方法的Page Method,於是之前的用法已經完全不兼容了,而且不是那麼輕易地就可以進行移植。其實方法總是有的,而且似乎也不是非常的費事,不過在這之前,我們還是來思考一下實例的Page Method與靜態的Page Method相關的問題吧。
靜態Page Method與實例Page Method的實現方式有什麼區別呢?靜態的Page Method的實現原理其實和客戶端調用Web Service如出一轍,幾乎沒有任何的區別。而實例Page Method在調用時和UpdatePanel有些接近——至少在一開始,因為它們為了獲得整個控件樹的信息,必須將頁面上的所有內容,例如所有輸入控件的值,連同ASP.NET存放在客戶端的ViewState等信息一並發送到服務器端。喔,這不就相當於一個完整的PostBack嗎?它與靜態Page Method相比,最大的劣勢也就在這裡:性能。實例Page Method在每次調用時都必須傳輸更多的數據,在構造一棵完整的控件樹,換來的是訪問控件樹的能力——再明確點說,換來的“只是”訪問控件樹的能力。其它功能的可以說幾乎完全沒有,例如對於控件的修改無法輸出到客戶端。
下面我們也必須考慮一下,靜態Page Method與實例Page Method相比,究竟有哪些限制呢?如果這種限制對於功能影響太大,那麼只能犧牲一些性能了。我們作最壞打算,也不過是相當於作了一次“完整”的刷新麼。估計最大的限制就是無法訪問頁面的“控件樹”了,例如下拉框的選項。不過就是因為這一點,我們就必須重建頁面的控件樹嗎?如果是客戶端控件的屬性,我們可以直接在客戶端得它的屬性之後,將它作為靜態Page Method的參數。如果是其它的值,我們在生成頁面時是如何獲得的,那麼就在靜態Page Method中再獲得一次吧。其實在我遇到的很多問題中,發現幾乎所有的情況都是可以使用“客戶端獲得數據,再作為服務器端方法的參數”這種做法。例如之前的例子就可以轉換成下面的做法。
[ScriptMethod]
public string GetString(string split, string text1, string text2)
{
return text1 + split + text2;
}
function successCallback(result)
{
...
}
var text1 = $get('<%= this.TextBox1.ClientID %>').value;
var text2 = $get('<%= this.TextBox2.ClientID %>').value;
PageMethods.GetString('|', text1, text2, successCallback);