One of the interesting things you can do with client-side JavaScript using the Ajax Client Library is to call a page method from client code. This means that if you have an existing page with a server-side C# or Visual Basic method, you can call the method from client-side JavaScript—and you can do it without a full- or partial-page postback.

This may seem to be a bit counterintuitive. Doesn’t server-side code in a web page in ASP.NET by definition require a postback? Not at all. ASP.NET allows this by turning the method into a proxy web service that is callable from client-side script, very much like calling a regular ASP.NET web service.

The sample code I'll use is an inventory-checking page. The user can enter a product ID from the Northwind products table to get the current number of items in stock.

There are a few things we'll need to do to set up and call a page method. First, of course, the code behind the page needs to have a GetInventory method that does the actual inventory lookup. The following C# and VB code implements that method and includes the WebMethod attribute to make it callable from script. To be a page method that is callable from script, it must be a static/shared method. With a page method, you don’t have to use the ScriptService attribute on the class. The code uses simple ADO.NET code to do the lookup, but you can of course use any of the more hip techniques you care to, such as LINQ and Entity Framework.

 [WebMethod]
public static short GetInventory(int ProductID)
{
    short retVal = 0;

    string strCnn =
        GetConnectionString("NorthwindConnectionString");
    string strSQL = "SELECT UnitsInStock FROM Products " +
        "WHERE ProductID = @ProductID";

    SqlConnection cnn = new SqlConnection(strCnn);
    cnn.Open();
    SqlCommand cmd = new SqlCommand(strSQL, cnn);
    cmd.Parameters.Add(new SqlParameter("@ProductID",
        ProductID));
    try
    {
        retVal = (short)cmd.ExecuteScalar();
    }
    catch (Exception e)
    {
        if (e.Message == "Object reference not set to an instance of an object.")
            throw new Exception(
                "Invalid product ID. Please try another.");
        else
            throw;
    }
    finally
    {
        cnn.Close();
    }

    return retVal;
}

<System.Web.Services.WebMethod()>
Public Shared Function GetInventory(
ByVal ProductID As Integer) As Short
    Dim retVal As Short = 0

    Dim strCnn As String =
     GetConnectionString("NorthwindConnectionString")

    Dim strSQL As String =
        "SELECT UnitsInStock FROM Products " &
        "WHERE ProductID = @ProductID"

    Dim cnn As New SqlConnection(strCnn)
    cnn.Open()

    Dim cmd As New SqlCommand(strSQL, cnn)
    cmd.Parameters.Add(New SqlParameter("@ProductID",
        ProductID))

    Try
        retVal = DirectCast(cmd.ExecuteScalar(), Short)

    Catch e As Exception
        If e.Message = "Object reference not set to an instance of an object." Then
            Throw New Exception(
                "Invalid product ID. Please try another.")
        Else
            Throw
        End If
    Finally
        cnn.Close()
    End Try

    Return retVal
End Function

The ScriptManager control as used in the page is defined a little differently in order to invoke a page method than you might use to call a web service. For example, you don't need to use a Services element because there is no need to identify the web service that the script will call. However, you do need to set the EnablePageMethods attribute to true. The following code is the ScriptManager control in the page. The rest of the HTML in the page remains the same as in the previous sample, where it was used to call a web service.

 <asp:ScriptManager ID="ScriptManager1"
    runat="server" EnablePageMethods="true">
</asp:ScriptManager>

The client getInventory function takes care of calling the page method. It does this via the PageMethods object, which was enabled by setting the ScriptManager’s EnablePageMethods attribute to true. (The page won’t recognize the PageMethods object without that attribute setting.)

 function getInventory()
{
    PageMethods.GetInventory($get("txtProductID").value,
        getInventorySuccess, getInventoryFail);
}

Here is the rest of the client-side JavaScript that sets up the button event handler as well as the getInventorySuccess and getInventoryFail functions.

 function pageLoad() {
    $addHandler($get("btnGetInventory"), "click",
        getInventory);
}

function getInventorySuccess(result) {
    $get("divInventory").innerHTML =
        "We have " + result + " in stock.";
}

function getInventoryFail(error) {
    $get("divInventory").innerHTML = error.get_message();
}

And here is the HTML for the body of the page, which contains a text box to get the inventory ID from the user and the button to call the getInventory function and invoke the page method.

Product ID:

<input id="txtProductID" type="text" value="1"
    style="width: 38px;" />
<input id="btnGetInventory" type="button"
    value="Get Current Inventory" />
<br /><br />
<div id="divInventory" style="font-weight:bold"></div>

If you’ve shied away from enriching your web applications with client-side JavaScript code in the past, you might find that the Ajax Client Library makes it easy enough that you might consider using it in the future. You’ll need to learn JavaScript a bit beyond the basics, because the library builds on JavaScript that might be confusing if you’re familiar only with server-side .NET languages. But the possibilities for enriching the usability and value of your applications will almost certainly be worthwhile in the long run. And calling page methods is just one of many ways to make use of the client library.

Don Kiely (donkiely@computer.org), MVP, MCSD, is a senior technology consultant, building custom applications and providing business and technology consulting services. His development work involves SQL Server, Visual Basic, C#, ASP.NET, and Microsoft Office.