Thursday, February 11, 2010

Call Server Side function from Client Side Code using PageMethods in ASP.NET AJAX

You cannot call server-side code ‘directly’ from client-side code. That isbecause by design, the server side code executes at server side andclient side code at the client. However there are some workarounds. Tocall serverside code from javascript, you will need to use AJAX, andthe easiest way out, is to use the ASP.NET AJAX Extensions.
Oneoption while using Microsoft ASP.NET AJAX is to call ASP.NET Webservices (.asmx files) from the browser by using client script. Thescript can call a webservice containing server-based methods (Webmethods) and invoke these methods without a postback and withoutrefreshing the whole page. However this approach could be overkillsometimes, to perform the simplest of tasks. Moreover the logic needsto be kept in a separate .asmx file. We need something that is more‘integrated’ with our solution.
Theoption we are going to use in this article involves PageMethods. APageMethod is basically a public static method that is exposed in thecode-behind of an aspx page and is callable from the client script.PageMethods are annotated with the [WebMethod] attribute. The pagemethods are rendered as inline JavaScript.
Letus explore PageMethods with an example. The example we will bediscussing here may not be the best example to explain PageMethods, butit will give you an idea of how to call server side code from clientside. In this example, we will be connecting to the Customers table inthe Northwind database. We will have some textboxes which will acceptthe CustomerID and in turn return the Contact Name of that Customer.The method returning ContactName will be called whenever the textboxloses focus. We will be using the onblur event where a javascript codewill take in the value(CustomerID) from the textbox. This javascriptfunction will then call a PageMethod (server side code) which returnsthe ContactName without any page refresh.
Iassume that you have downloaded and installed ASP.NET AJAX extensionsfor ASP.NET 2.0. If not, I would advise you to download the extensionsfrom hereand install it before moving ahead. At any point of time, if you find adifficulty in understanding the code, download the sample projectattached with this article at the end.
Step 1:Create an ASP.NET AJAX enabled website. Go to File > New >Website > ASP.NET AJAX-Enabled Web Site. Give the solution a nameand location and click Ok.
Step 2:Drag and drop 2 labels and 4 textbox controls. We will be accepting theCustomerID from the user in the 2 textboxes and displaying the‘ContactName’ in the other two textboxes. The textboxes that willdisplay ‘ContactName’ has some properties set that will make it appearas a label without a border. Just set the BorderStyle=None,BorderColor=Transparent and ReadOnly=True. The markup will look similarto the following:
<form id="form1" runat="server">    
        <asp:ScriptManager ID="ScriptManager1" runat="server"/>
        <div>
        <asp:Label ID="lblCustId1" runat="server" Text="Customer ID 1"></asp:Label>
        <asp:TextBox ID="txtId1" runat="server"></asp:TextBox><br />
            <asp:TextBox ID="txtContact1" runat="server" BorderColor="Transparent" BorderStyle="None"
                ReadOnly="True"></asp:TextBox><br />
        <br />
        <asp:Label ID="lblCustId2" runat="server" Text="Customer ID 2"></asp:Label>
        &nbsp;
        <asp:TextBox ID="txtId2" runat="server"></asp:TextBox><br />
            <asp:TextBox ID="txtContact2" runat="server" BorderColor="Transparent" BorderStyle="None"
                ReadOnly="True"></asp:TextBox>&nbsp;<br />
            </div>
    </form>
Before moving ahead, we will store our connection string information in the Web.config. Add the following tag below your </configSections> tag. Remember we have created an ‘ASP.NET AJAX enabled website’. The tag </configSections> along with some other tags automatically get added to the web.config.
<connectionStrings>
            <removename="all"/>
            <addname="NorthwindConnectionString"connectionString="Data Source=(local); Initial Catalog=Northwind; Integrated Security = SSPI;"/>
      </connectionStrings>
Step 3:Currently we will add a method, ‘GetContactName()’ which will accept aCustomerID and return the Contact Name information from the Northwinddatabase, Customer table. We will then transform this method as aPageMethod.
C#
public static string GetContactName(string custid)
    {
        if (custid == null || custid.Length == 0)
            return String.Empty;
        SqlConnection conn = null;
        try
        {
            string connection = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
            conn = new SqlConnection(connection);
            string sql = "Select ContactName from Customers where CustomerId = @CustID";
            SqlCommand cmd = new SqlCommand(sql, conn);
            cmd.Parameters.AddWithValue("CustID", custid);
            conn.Open();
            string contNm = Convert.ToString(cmd.ExecuteScalar());
            return contNm;
        }
        catch (SqlException ex)
        {
            return "error";
        }
        finally
        {
            conn.Close();
        }
    }
VB.NET
 Public Shared Function GetContactName(ByVal custid As String) As String
        If custid Is Nothing OrElse custid.Length = 0 Then
            Return String.Empty
        End If
        Dim conn As SqlConnection = Nothing
        Try
            Dim connection As String = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString
            conn = New SqlConnection(connection)
            Dim sql As String = "Select ContactName from Customers where CustomerId = @CustID"
            Dim cmd As SqlCommand = New SqlCommand(sql, conn)
            cmd.Parameters.AddWithValue("CustID", custid)
            conn.Open()
            Dim contNm As String = Convert.ToString(cmd.ExecuteScalar())
            Return contNm
        Catch ex As SqlException
            Return "error"
        Finally
            conn.Close()
        End Try
    End Function
Step 4:We will now transform this method as a PageMethod and then call thismethod GetContactName() from client side code; i.e. using JavaScript.To enable the method as a PageMethod, add the attribute [WebMethod] ontop of the method:
C#
[System.Web.Services.WebMethod]
public static string GetContactName(string custid)
{
}
VB.NET
<System.Web.Services.WebMethod()> _
    Public Shared Function GetContactName(ByVal custid As String) As String
   End Function
At the sametime, add the attribute EnablePageMethods="true" to the ScriptManager as shown below:
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"/>
Step 5:Let us now create the JavaScript that will call this server side code.Add a javascript file called script.js to your solution (Right ClickProject > Add New Item > Jscript File > Rename file toscript.js). Add the following code to the javascript file.
function CallMe(src,dest)
 {    
     var ctrl = document.getElementById(src);
     // call server side method
     PageMethods.GetContactName(ctrl.value, CallSuccess, CallFailed, dest);
 }
 // set the destination textbox value with the ContactName
 function CallSuccess(res, destCtrl)
 {    
     var dest = document.getElementById(destCtrl);
     dest.value = res;
 }
 // alert message on some failure
 function CallFailed(res, destCtrl)
 {
     alert(res.get_message());
 }
Step 6:We now need to reference this JavaScript file from our aspx page andinvoke the ‘CallMe()’ method whenever the textbox loses focus. To do so:
Add a reference to the javascript file in the body tag as shown below:
<body>
<script type="text/javascript" language="javascript" src="script.js"> </script>
    <form id="form1" runat="server">    
………
Step 7: To invoke the methods whenever the textbox looses focus, add these lines of code in the Page_Load() event
C#
if (!Page.IsPostBack)
        {
            txtId1.Attributes.Add("onblur", "javascript:CallMe('" + txtId1.ClientID + "', '" + txtContact1.ClientID + "')");
            txtId2.Attributes.Add("onblur", "javascript:CallMe('" + txtId2.ClientID + "', '" + txtContact2.ClientID + "')");
        }
VB.NET
If (Not Page.IsPostBack) Then
                 txtId1.Attributes.Add("onblur", "javascript:CallMe('" &txtId1.ClientID & "', '" & txtContact1.ClientID & "')")
                 txtId2.Attributes.Add("onblur", "javascript:CallMe('" &txtId2.ClientID & "', '" & txtContact2.ClientID & "')")
End If
Asshown above, we are using the Attributes.Add that lets us add anattribute to the server control’s System.Web.UI.AttributeCollectionobject. The function ‘CallMe’ kept in the ‘script.js’ file will beinvoked. We are passing the source and destination textboxes asparameters. The source textbox will contain the CustomerID. TheCustomerID will be looked up in the Customers table and thecorresponding ‘ContactName’ will be retrieved in the destinationtextbox.
Wellthat is all that is needed to invoke server side code from client side.Run the code. Type ‘ALFKI’ in the first textbox and hit the tab key.You will see that the javascript function goes ahead and calls thePageMethod GetContactName() using PageMethods.GetContactName. Itpasses the value of the source textbox which contains the CustomerID.The ‘ContactName’ returned is displayed in the second textbox below thefirst one, in our case the value displayed is ‘Maria Anders’.

3 comments:

Rajesh jha said...

Very Very nice solution it will solve my problem
But i have a confusion i want to fetch more than one item like on selection of customer ID the result should show his name and contact no. both in separate textbox. how i will do this?
Pl. give me solution soon i will be highly obolised

Rinkesh Jain said...

Best Example to learn about Page methods in the begining....

THANKS A LOT

Rinkesh Jain said...

Thanks