How To Issue Server Callbacks

Callbacks were introduced in ASP.NET 2.0 and is a simple mechanism for calling page or control functionality without page rendering and without the user noticing a post back.

For a page or control to handle callbacks, all it needs is to implement the ICallbackEventHandler Interface.

When the client calls back to de page or control, the initial state of the controls is posted along with the control being called upon in the __CALLBACKID field and the callback parameter in the __CALLBACKPARAM field.

It’s quite a simple procedure.

But what if you want to issue a callback server side?

In order for a request to be identified as a callback (IsCallback), the request must be a postback (IsPostback) and the before mentioned fields must be in the post data of the request. On the other hand, for a request to be considered a postback, the level of server calls (Transfer or Execute) must be 0 (meaning that the current request hasn’t made any Transfer or Execute calls) or the type of the page is the same of the Handler for the current request and the HTTP method is POST.

Changing the HTTP method is (as far as I know) impossible. So, if the request is not already a POST, there’s no way to issue a callback.

Setting the post data is easier. All it’s needed is to override the page’s DeterminePostBackMode method (or in a page adapter) and return the post data previously saved in a context item. Something like this:

protected override NameValueCollection DeterminePostBackMode()
{
    NameValueCollection postBackMode = Context.Items["callbackPostData"] as NameValueCollection;

    return (postBackMode != null) ? postBackMode : base.DeterminePostBackMode();
}

And issue a callback is something like this:

IHttpHandler handler = this.Context.Handler;
try
{
    NameValueCollection postData = new NameValueCollection();
    postData.Add("__CALLBACKID", sender);
    postData.Add("__CALLBACKPARAM", this.argument.Text);

    Context.Items["callbackPostData"] = postData;

    Page calledPage = (Page)PageParser.GetCompiledPageInstance("~/Callback1.aspx", this.Server.MapPath("~/Callback1.aspx"), this.Context);

    this.Context.Handler = calledPage;

    StringWriter writer = new StringWriter();

    Server.Execute(calledPage, writer, false);

    this.response.Text = writer.ToString();
}
finally
{
    this.Context.Handler = handler;
}

You can find an implementation of a caller and a called page here.

Comments are closed.