A good place to start is right here http://www.asp.net/ajax/documentation/live/tutorials/ExposingWebServicesToAJAXTutorial.aspx
Scroll to the bottom of the page and read "Calling Static Methods in an ASP.NET Web Page"
Also, here is a more detailed example of using PageMethods. It allows you to select an option from a DropDownList, which triggers a PageMethod to retrieve some data from the server to populate a second DropDownList.
ASPX Page
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AsyncDDL_Example2.aspx.cs"
Inherits="AsyncDDL_Example2" %>
<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
<script type="text/javascript">
Sys.Application.add_init(Page_Init);
Sys.Application.add_unload(Page_Unload);
function Page_Init(sender)
{
// Get variable pointing to DDL
var ddlCountry = $get('<%=ddlCountry.ClientID %>');
// Add event handler to trigger PageMethod
$addHandler(ddlCountry,'change',ddlCountry_changed);
}
function Page_Unload() {
// Get variable pointing to DDL
var ddlCountry = $get('<%=ddlCountry.ClientID %>');
// Always remove event handlers to prevent memory leaks
$removeHandler(ddlCountry,'change',ddlCountry_changed);
}
// Event handler for ddlCountry.
// Will send the Country ID to the server and get a list of Districts back
function ddlCountry_changed(evt) {
// This initiates the call to the server-side method in your code-behind
// The parameters are as follows:
// 1st : The parameters expected by your code-behind method (in this case there's just 1: ID)
// 2nd : Callback method when the server responds successfully
// 3rd : Callback method when the server responds with an error (optional)
// 4th : Specify a user context object (optional - not shown)
PageMethods.GetDistricts(evt.target.selectedIndex, GetDistricts_Success, GetDistricts_Failure);
}
// Success callback method
// This method receives the result from your server-side method in the result parameter
// In this case it is an array of objects function GetDistricts_Success(results) {
if (results) {
// There is no code block here because ddlDistrict is not a server control.
// It's just a <select> so the ID won't get altered during compilation
var ddl = $get('ddlDistrict');
// Remove any existing list items
ddl.options.length = 0;
// Iterate over the array of districts returned from the server
// and create new ListItems (i.e. new Option(...)) for each district
for (district in results) {
ddl.options.options[ddl.options.length]
= new Option(results[district].Name, results[district].ID);
}
}
else
alert("An unexpected error occurred"); // Shouldn't occur if things are coded properly
}
// Failure callback method
function GetDistricts_Failure(error) {
if (error) {
alert(error.get_message());
}
else
alert("An unexpeceted error occurred"); // Shouldn't occur if things are coded properly
}
</script>
<asp:DropDownList ID="ddlCountry" runat="server" AppendDataBoundItems="true">
<asp:ListItem Text="Select..." Value="-1"></asp:ListItem>
</asp:DropDownList>
<select id="ddlDistrict">
</select>
</div>
</form>
</body>
</html>
C# Code Behind
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class AsyncDDL_Example2 : System.Web.UI.Page
{
// You can ignore this part. I'm just creating a fake local datasource so there's no
// dependency on sql in this example. You will of course have to use a real datasource.
#region FakeDataSource
public class Country
{
public int ID { get; set; }
public string Name { get; set; }
}
public class District
{
public int ID { get; set; }
public int CountryID { get; set; }
public string Name { get; set; }
}
public static Country[] _countries;
public static Country[] countries
{
get
{
if (_countries == null)
{
_countries = new Country[] {
new Country {
ID=1,
Name="Canada"
},
new Country {
ID=2,
Name="USA"
}
};
}
return _countries;
}
}
public static District[] _districts;
public static District[] districts
{
get
{
if (_districts == null)
{
_districts = new District[] {
new District {
ID=1,
Name="British Columbia",
CountryID=1
},
new District {
ID=2,
Name="Alberta",
CountryID=1
},
new District {
ID=3,
Name="Saskatchewan",
CountryID=1
},
new District {
ID=4,
Name="Manitoba",
CountryID=1
},
new District {
ID=5,
Name="Ontairo",
CountryID=1
},
new District {
ID=6,
Name="Quebec",
CountryID=1
},
new District {
ID=7,
Name="Arizona",
CountryID=2
},
new District {
ID=8,
Name="Oregon",
CountryID=2
},
new District {
ID=9,
Name="California",
CountryID=2
},
new District {
ID=10,
Name="Texas",
CountryID=2
},
new District {
ID=11,
Name="Florida",
CountryID=2
}
};
}
return _districts;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ddlCountry.DataSource = countries;
ddlCountry.DataTextField = "Name";
ddlCountry.DataValueField = "ID";
ddlCountry.DataBind();
}
}
// This is the Page Method
// There are 2 distinct features
// 1. It has the [WebMethod()] attribute
// 2. It is declared public static
// Also notice that it can return any type
// In this case I am using an array of user-defined datatype District
// The District[] gets serialized into JSON so it is readable in javascript
// using pretty much the same syntax as you'd use on the server
[System.Web.Services.WebMethod()]
public static District[] GetDistricts(int CountryID)
{
// This is a LINQ query assembling by array
// You can of course use your own logic if you're not comfortable with LINQ
// or cannot use LINQ because your project is NET 2.0
District[] filteredDistricts =
(from d in districts
where d.CountryID == CountryID
select d).ToArray();
return filteredDistricts;
}
}