PAGES

6

Apr 06

ASP.NET 2.0 Script Callbacks for Web Page AutoRefresh



Recently I was working on a website requires client refresh when state changed on the server. We wanted to implement this without posting the page back to the server constantly. The solution to this problem was to implement an out of band call (AJAX) to the server from a javascript timer. This call can then check with the server if a post back should be done to refresh the system.

To implement the out of band call, I used asp.net 2.0 script callbacks. Script callbacks uses XmlHTTP to communicate with the server, and instead of the rs.htm and rs.asp file (like older techniques used to us) ASP.Net 2.0 uses the a script-library named CallBackManager.

The client makes the call of a client-side method that will use the CallBackManager. The CallBackManager creates the request to an .aspx page on the server. The server processes the page and its events and makes the call of the sever-side function. The CallBackManager then parses the server response and make the call to a callback method located on the client-side. The CallBackManager must know the name of the client-side callback method. The CallbackManager must know which method it should call on the client-side. This is accomplished by using the GetCallBackEventReference method of the page. With this method we could also specify which method the CallbackManager should call if the server throws an exception.

Let’s examine the code elements that are used to make this work.

The System.Web.UI.ICallbackEventHandler must be implemented for using callback events.

<%@ page language=”C#” %>
<%@ implements interface=”System.Web.UI.ICallbackEventHandler” %>

The Code Behind for the page implementing ICallbackEventHandler must implement one method – RaiseCallbackEvent- to make the callback work. This method takes one argument which will contain the data from the client, and return a string value back to the client. In my case the RaiseCallbackEvent checks if state on the server has changed (compared to the state in Session for this user). If so, the client’s view of the application should be refreshed. _returnFromServer is a private member variable of the codeBehind file that is set and used to return values to the client javascript method.

public void RaiseCallbackEvent(string eventArgs)
{
if (Global.IsStateChagedChanged((int)Session["clientState"])
{
this._returnFromServer = “Do Postback”;
}
else
{
this._returnFromServer = “”;
}
}

The next step is to set a reference within the CodeBehind to the client script that will be called back. This is accomplished using the GetCallbackEventReference method. This method has 3 overrides, in this case the following signature is used.

public string GetCallbackEventReference(
Control control,
string argument,
string clientCallback,
string context,
string clientErrorCallback)

The following code uses the GetCallbackEventReference to specify the client-side callback methods and the control that implements ICallbackEventHandler. In this example it’s the current page that has implemented the ICallbackEventHandler. So the current page object is passed to the method. When the server-side method has been executed the ClientCallback method on the client-side will be executed. If the servers throw an exception, the ClientErrorCallback will be executed on the client-side. The arg and ctx are names of the arguments of the client-side event that calls the server-side method. This code is part of the Page_Load for the page.

string src = Page.ClientScript.GetCallbackEventReference(
this,
“arg”,
“ClientCallback_Refresh”,
“ctx”,
“ClientErrorCallback_Refresh”,
false);

The code above provides the needed client reference for the loaded page. In addition to this, the page needs to provide a javascript function that can be executed from the client to execute the call to the server. This is done using the RegisterClientScriptBlock function as shown here.

string mainSrc = @”function CheckRefresh(arg, ctx)
{ ”
+ src + “; }”;

Page.ClientScript.RegisterClientScriptBlock(
this.GetType(),
“CheckRefresh”,
mainSrc,
true);

The RegisterClientScriptBlock above will generate in the rendered html to the client:

function CheckRefresh(arg, ctx)
{
WebForm_DoCallback(
‘__Page’,arg,ClientCallback_Refresh,ctx,ClientErrorCallback_Refresh,false);
}

This __doCallback method takes five arguments, the current page, the argument value sent into the RaiseCallbackMethod, the client-side callback method, the context value that will be sent to the client-side callback method, and the last argument is the client-side method that will be triggered if the server throws an exception.

The last piece of code needed in the code-behind is a simple accessor method that provides access to member variable set during RaiseCallbackEvent that is used to return the result to the client scripts. The GetCallbackResult is used for this.

public string GetCallbackResult()
{
return this._returnFromServer;
}

With all the code in place in the code-behind, we need some simple javascript on the page to initiate the call back by executing the server generated CheckRefresh and checking the results. In this case, the timer method is executed every 10 seconds using the javascript function SetInterval(10000).

function CheckRefresh_Timer()
{
myMessage.hide()
CheckRefresh(
“”, “”);
}

function ClientCallback_Refresh( result, context )
{
// initiate a postback to refresh data
if(result == “Do Postback”)
{
__doPostBack(
‘ctl00$pageMainColumn$lbStateChange’,);
}
}

function ClientErrorCallback_Refresh( error, context )
{
//log or ignore error
}

Notice that when state changes, the page submits to the server via a button. This allows a specifically targeted postback(ie. Fire a button event handler and the page_load with IsPostback = true) to the server rather than a general page refresh. This is done by declaring an “invisible” button. The code below shows the declaration of the button.

<div style=“visibility:hidden;”>
<asp:LinkButton ID
=“lbStateChange” runat=“server” OnClick=“lbStateChange_Click” >state change


The last important concept with respect to Script Callbacks is the execution of page_load. It is important to understand that the page_load of the page implementing the CallBackEventHandler is executed with Page.IsPostback = true each time a client calls back. Therefore, it is vital to ensure that this code path executes the smallest amount of code possible.

Overall, this seemed much more complicated that it actually was. It is just a matter of putting all the pieces together. The result is a client experience that can remain in synch with the server without disrupting general navigation and site usage.

14 comments , permalink


  • http://

    I am doing this in VB, and i get the following error:
    must implement ”Function GetCallbackResult() As String” for interface ”System.Web.UI.ICallbackEventHandler”.

    I am using code straight of msdn to test this. Do i have to add a reference to a specific dll or am I missing an ”import” statement in my code behind?

    p.s. I am declaring code behind class as follows:

    Partial Class _Default
    Inherits System.Web.UI.Page
    Implements _ System.Web.UI.ICallbackEventHandler
    thanks for your help.

  • http://

    Great!

    Thanks for this simple and clear article! It got me started right away!

  • http://

    jason,
    did you maybe forget to imlement the method GetCallbackResult() in your code?

  • http://

    sdd

  • http://

    Jason…I wasted hours with your same problem. Here is the VB.NET solution.

    Change: Public Function GetCallbackResult() As String
    To: Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult

    Change: Public Sub RaiseCallbackEvent(ByVal eventArgument As String)
    To: Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent

    Why VB requires this? I don”t know, but it works. l8tr…

  • http://

    jm

  • http://

    Please send me all the code snippet at one place.so that it make more sense to implement easily.

  • http://

    Can you add additional scripts to a page with a callback?

  • VJ

    Can you please post the entire code snippet. I”m working on a similar application and would like to experiment with the code

  • VJ

    Can you please post the entire code snippet. I”m working on a similar application and would like to experiment with the code

  • 4tr4r4

    frwetwetweere

  • http://

    Thanks for the post, it saved me time, tnx SrChas

  • http://

    Great Work Man!!!!!

  • http://

    Can you please post the entire code