Async Callbacks in ASP.NET 2.0 PDC Release - What's wrong with this picture?

I was talking to my mate Darren a while ago and I mentioned that I was thinking of writing an ASP.NET control to allow me to easily add asynchronous callbacks to my web forms without having to write much (or any) code by wrapping the WebService DHTML behavior. He flippantly told me that async callbacks were ‘baked in’ to Whidbey. I lost interest in my control idea but never got around to looking into the Whidbey callback facilities until the week-end. When I did I was a little bit disappointed. The way callbacks work is that your page implements an interface ICallbackEventHandler which requires that you implement a single method called RaiseCallbackEvent() . The page object also has a method called GetCallbackEventReference() for getting some javascript to perform the callback from the client which you can then register in your page. I wrote a sample which I put up on GotDotNet showing how to do this (it should be available soon).

The problem I have is with the method signature for RaiseCallbackEvent - it takes a single string as an argument and returns a string. This seems fundamentally flawed for two reasons - suppose you have two text boxes on a form (say a customer code field and a product code field) and you want to asynchronously return some data for each one when the user leaves the each box. Say for the customer you want to return the full name of the person and their shipping address to show to the user, and for the product you want to show the amount you have in stock. You can wire up each text box to call back to the server easily enough, but when RaiseCallbackEvent (which only takes a single string as an argument) is called how do you know who is calling you back? Is it the textbox with the product code sending you a product code and expecting the number of units you have in the shed, or is it the customer code text box calling back and wanting the mailing address for the customer? You can fairly easily get around this by sending some hard-coded string concatenated to the front of the “real” value you’re sending back (the product or customer code in our example) and then parse it out on the server, but it is a bit of a kludge.

The second problem I have is that RaiseCallbackEvent can only return one thing, a string - no complex types, no collections, no arrays. Just a string. This leaves you in the un-enviable position of having to serialize anything else into a string and parse it out in client-side script, or forget about async callbacks for everything moderately complicated.

I know what you’re probably thinking - this is all complicated stuff, you can’t have everything. I would probably accept that except there already is a technology that lets you call back asychronously from client-side script, pass (almost) whatever you like, get back almost anything you like and have multiple end-points with no ambiguity as to why you are calling back (do I need to return a billing address, or is it a product quantity)? The technology I am refering to of course is WebServices and the WebService DHTML behavior.

All the things I’ve said so far are “as of the PDC release” - these problems may have been addressed already. Also there is scant to no documentation on any of this at this point so perhaps I have completely the wrong end of the stick. Also this API might have been designed more for control builders to add async. facilities to individual controls, rather than for page builders to add async facilities to whole pages. In the control scenario (which typically have a more singular focus) this method might be forgivable (but still not that great). As it stands RasieCallbackEvent seems pretty weak. Instead what about an attribute that you could add to a method that would make it a potential target for client callbacks, and have GetCallbackEventReference() and the page handle the wiring up? Does anybody know more about this API? Are there any changes pending for it in the beta versions?

Update: Here is my ASP.NET 2.0 asynchronous callback demo on GotDotNet

Update 2: Here is an article on DevX dealing with the Async. callback facilities in ASP.NET 2.0 “Whidbey” http://www.devx.com/dotnet/Article/20239/0/page/1 - the author does not seem to make any judgement calls regarding the design of this API, but the article is titled “Whidbey Simplifies Browser Client Script Callbacks“. Simplify is indeed the right word.

Comments

JosephCooney
FxCop Rule Libraries for ASP.NET?
4/03/2004 3:58:00 PM
JosephCooney
Async Callbacks in ASP.NET 2.0 VS 2005 CTP Release
31/03/2004 7:49:00 PM
Bertrand Le Roy
The callback feature IS aimed at control developers. You seem to forget a small detail about behaviors: they’re only available on IE. The ASP.NET callback feature already works on IE and Firefox and the final version will work on more browsers.
The example about wiring up several text boxes can be solved by the CallbackMultiplexer sample control that’s included in my sample workspace (http://www.gotdotnet.com/workspaces/workspace.aspx?id=cb2543cb-12ec-4ea1-883f-757ff2de19e8).
Another problem with the web service behavior when compared with the ASP.NET callbacks is that you need to create a web service for each control, whereas with callbacks, everything is integrated in the page and control lifecycle.
That’s very important: with web services, there’s no way you’re going to be able to access other controls on the page and integrate them in your update procedure. With callbacks, your update procedure executes in the context of the page, so all controls are fully available.
10/04/2005 10:15:00 PM
JosephCooney
I was less-than-impressed with the async callback feature since it did NOT work in firefox IIRR in the PDC release that I tested. For control developers I can honestly see the benefit, but you don’t necessarily need 1 web service per control, you just need one webmethod per type of async operation you want to perform. I don’t really buy into the "can’t access other controls on the page" argument. If you need the state of the controls to be sent back you can just do that from your callback code. You can’t change the properties of the control inside the callback anyway, becuase the viewstate has already been written to the client. I love the async idea (especially the part about making it easy) - I just wish it could have been more strongly typed.
12/04/2005 1:55:00 AM
Bertrand Le Roy
Copied from my blog:
It didn’t work with Firefox in the PDC build, but let’s be honest, what did? The PDC build was an early alpha. Beta 2 should be available any time now.
If you’re using callbacks, you can have the same reusability you have with web services by isolating the code in a separate method and just calling that from your event handlers. Actually, it is pretty obvious that this is the good practice if your callback logic is not specific to this control.
The only state you can use with the web service approach is the client-side state, not the server-side state. That means more client code, and nobody want that, right? With callbacks, you just have access to your other controls as usual, it just works. With web services, your client-side code has to take the client-side state (if it exists at all in a usable form: think about the state of a TreeView) and package it into XML for the web service to consume.
The real reason why the ViewState is not updated during callbacks is that the page lifecycle is not completely executed, and because several asynchronous callbacks can happen at the same time in the current build (which is not beta 2). Otherwise, it would be fairly easy to send the new value of the viewstate back to the client.
Anyway, I’m not talking about changing the state of other controls on the page, I’m talking about using it.
The point is that ASP.NET callbacks are fully integrated into the page lifecycle and web services are not. This has many advantages, another one being ease of writing.
I understand your point about strongly typing. The problem is that there is a huge impedance mismatch between the JavaScript type system and the SOAP and .NET type systems. If you go the strongly-typed way client-side, where do you stop?
I kind of like the frameworks that try to give you client-side an object hierarchy that looks like what you have server-side, but that a very leaky abstraction. It looks nice, but it is actually an illusion IMHO. It increases the complexity of the client-script, and it’s only nicer if you actually intend to write a lot of client-side code and need a clean object model there. The truth is, most people don’t want to touch client-side code, they want to write as little as possible. So far, strings have been just fine for all our scenarios. We do some simple parsing in the TreeView case, but TreeView is already a very complex control.
Another thing to consider is that the callback API is just that: a relatively low-level API that enables you to forget about the complexities of communicating cross-browser with the server. The idea is that people will build stuff on top of it. For example, I don’t know if you checked out my samples, but there is a very interesting thingy in there that’s called CallbackMultiplexer and it does something like a more strongly-typed callback in a very transparent way. You could very well build a control on top of our callback API that does marshalling in a more strongly-typed way, à la Web Service. After all, XML is just a way to marshal strongly-typed data using a string.
You know what, I think I agree with you that there are scenarios where you will want something more strongly-typed that a string, and I think I’ll build a control that does that for you. I’ll add it to the sample collection when it’s ready. :)
Thanks for the comments.
12/04/2005 12:28:00 PM
Steve
"I understand your point about strongly typing. The problem is that there is a huge impedance mismatch between the JavaScript type system and the SOAP and .NET type systems. If you go the strongly-typed way client-side, where do you stop?"

XML

4/05/2005 4:25:00 AM
Steve
I see that PowerWEB controls by Dart do all this - why doesn’t Microsoft make their controls act this way by default?

Is there a reason Microsoft can’t make C# also work client side so that is eliminates the need for javascript and we can just use objects and strong types?
4/05/2005 4:39:00 AM
Lukash
a nice free library is doing it well : AJAX.NET
(http://ajax.schwarz-interactive.de/csharpsample/default.aspx)
31/05/2005 1:25:00 AM
Shiloh
Actually behaviors are/ or can be crossbroweser. I have played around a little with the examples listed but enough to know the limits
3/01/2006 11:30:00 AM
Shiloh
3/01/2006 11:31:00 AM
JosephCooney
Thanks Shiloh - at the time I wrote this post behaviors in Mozilla were not well understood. I still haven’t tried out the webservice behavior in mozilla, and would be interested to see if it worked.
3/01/2006 5:17:00 PM