There’s a lot of confusion about how asynchronous communication works in RIA’s
such as Silverlight, GWT and Javascript. When I start talking about the problems of
concurrency control, many people tell me that there aren’t any concurrency problems
since everything runs in a single thread. [1]
It’s important to understand the basics of what is going on when you’re writing
asynchronous code, so I’ve put together a simple example to show how execution
works in RIA’s and how race conditions are possible. This example applies to
Javascript, Silverlight, GWT and Flex, as well as a number of other environments
based on Javascript. This example doesn’t represent best practices, but rather what
can happen when you’re not using a proactive strategy that eliminates concurrency problems
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
Keeping track of state in asynchronous callbacks
1. Generation 5 » Keeping Track Of State In Asynchronous Callbacks
Subscribe to our RSS Feed | About Us
Keeping Track Of State In Asynchronous Callbacks
When you’re writing applications that use asynchronous callbacks (i.e. Silverlight,
AJAX, or GWT) you’ll eventually run into the problem of keeping track of the context
that a request is being done in. This isn’t a problem in synchronous programming,
because local variables continue to exist after one function calls another function
synchronously:
int AddToCount(int amount,string countId)
int countValue=GetCount(countId);
return countValue+amount;
}
{
This doesn’t work if the GetCount function is asynchronous, where we need to write
something like
int AddToCountBegin(int amount,string countId,CountCallback outerCallback) {
GetCountBegin(countId,AddToCountCallback);
}
void AddToCountCallback(int countValue) {
... some code to get the values of amount and outerCallback ...
outerCallback(countValue+amount);
}
Several things change in this example: (i) the AddToCount function gets broken up
into two functions: one that does the work before the GetCount invocation, and one
that does the work after GetCount completes. (ii) We can’t return a meaningful value
from AddToCountCallback, so it needs to ‘return’ a value via a specified callback
function. (iii) Finally, the values of outerCallback and amount aren’t automatically
shared between the functions, so we need to make sure that they are carried over
somehow.
There are three ways of passing context from a function that calls and asynchronous
function to the callback function:
1. As an argument to the callback function
2. As an instance variable of the class of which the callback function is a class
3. Via a closure
Let’s talk about these alternatives:
1. Argument to the Callback Function
In this case, a context object is passed to the asynchronous function, which passes
the context object to the callback. The advantage here is that there aren’t any
constraints on how the callback function is implemented, other than by accepting the
context object as a callback. In particular, the callback function can be static. A major
disadvantage is that the asynchronous function has to support this: it has to accept a
state object which it later passes to the callback function.
The implementation of HttpWebRequest.BeginGetResponse(AsyncCallback a,Object
state) in the Silverlight libraries is a nice example. If you wish to pass a context object
to the AsyncCallback, you can pass it in the second parameter, state. Your callback
function will implement the AsyncCallback delegate, and will get something that
implements IAsyncResult as a parameter. The state that you passed into
BeginGetResponse will come back in the IAsyncResult.AsyncState property. For
example:
class MyHttpContext {
public HttpWebRequest Request;
public SomeObject FirstContextParameter;
public AnotherObject AnotherContextParameter;
}
protected void myHttpCallback(IAsyncResult abstractResult) {
MyHttpContext context = (MyHttpContext) abstractResult.AsyncState;
HttpWebResponse Response=(HttpWebResponse)
context.Request.EndGetResponse(abstractResult);
}
http://gen5.info/q/2008/06/02/keeping-track-of-state-in-asynchronous-callbacks/[1/12/2014 9:30:30 PM]
Search for:
Search
Archives
June 2012 (1)
August 2010 (1)
May 2010 (1)
June 2009 (2)
April 2009 (1)
March 2009 (1)
February 2009 (3)
January 2009 (3)
November 2008 (1)
August 2008 (2)
July 2008 (5)
June 2008 (5)
May 2008 (2)
April 2008 (6)
March 2008 (8)
June 2006 (1)
February 2006 (1)
Categories
AJAX (2)
Asynchronous Communications (16)
Biology (1)
Books (1)
Design (1)
Distributed (1)
Exceptions (2)
Functional Programming (1)
GIS (1)
Ithaca (1)
Japan (1)
Math (1)
Media (3)
Nature (1)
Semantic Web (3)
Tools (28)
CRUD (1)
Dot Net (17)
Freebase (2)
GWT (9)
Java (7)
Linq (2)
PHP (6)
Server Frameworks (1)
Silverlight (12)
SQL (5)
Uncategorized (1)
Web (2)
Analytics (1)
2. Generation 5 » Keeping Track Of State In Asynchronous Callbacks
public doHttpRequest(...) {
...
MyHttpContext context=new MyHttpContext();
context.Request=Request;
context.FirstContextParameter = ... some value ...;
context.AnotherContextParameter = .. another value ...;
Request.BeginGetResponse();
Request.Callback(myHttpCallback,context);
}
Note that, in this API, the Request object needs to be available in myHttpCallback
because myHttpCallbacks get the response by calling the
HttpWebResponse.EndGetResponse() method. We could simply pass the Request
object in the state parameter, but we’re passing an object we defined,
myHttpCallback, because we’d like to carry additional state into myHttpCallback.
Note that the corresponding method for doing XMLHttpRequests in GWT, the use of a
RequestBuilder object doesn’t allow using method (1) to pass context information —
there is no state parameter. in GWT you need to use method (2) or (3) to pass
context at the RequestBuilder or GWT RPC level. You’re free, of course, to use method
(1) when you’re chaining asynchronous callbacks: however, method (2) is more
natural in Java where, instead of a delegate, you need to pass an object reference to
designate a callback function.
2. Instance Variable Of The Callback Function’s Class
Functions (or Methods) are always attached to a class in C# and Java: thus, the state
of a callback function can be kept in either static or instance variables of the
associated class. I don’t advise using static variables for this, because it’s possible for
more than one asynchronous request to be flight at a time: if two request store state
in the same variables, you’ll introduce race conditions that will cause a world of pain.
(see how race conditions arise in asynchronous communications.)
Method 2 is particularly effective when both the calling and the callback functions are
methods of the same class. Using objects whose lifecycle is linked to a single
asynchronous request is an effective way to avoid conflicts between requests (see the
asynchronous command pattern and asynchronous functions.)
Here’s an example, lifted from the asynchronous functions article:
public class HttpGet : IAsyncFunction<String>
{
private Uri Path;
private CallbackFunction<String> OuterCallback;
private HttpWebRequest Request;
public HttpGet(Uri path)
{
Path = path;
}
public void Execute(CallbackFunction<String> outerCallback)
{
OuterCallback = outerCallback;
try
{
Request = (HttpWebRequest)WebRequest.Create(Path);
Request.Method = "GET";
Request.BeginGetRequestStream(InnerCallback,null);
}
catch (Exception ex)
{
OuterCallback(CallbackReturnValue<String>.CreateError(ex));
}
}
public void InnerCallback(IAsyncResult result)
{
try
{
HttpWebResponse response = (HttpWebResponse)
Request.EndGetResponse(result);
TextReader reader = new
StreamReader(response.GetResponseStream());
OuterCallback(CallbackReturnValue<String>.CreateOk(reader.ReadToEnd()));
} catch(Exception ex) {
OuterCallback(CallbackReturnValue<String>.CreateError(ex));
}
}
}
Note that two pieces of context are being passed into the callback function: an
HttpWebRequest object named Request (necessary to get the response) and a
CallbackFunction<String> delegate named OuterCallback that receives the return
value of the asynchronous function.
Unlike Method 1, Method 2 makes it possible to keep an unlimited number of context
variables that are unique to a particular case in a manner that is both typesafe and
http://gen5.info/q/2008/06/02/keeping-track-of-state-in-asynchronous-callbacks/[1/12/2014 9:30:30 PM]
3. Generation 5 » Keeping Track Of State In Asynchronous Callbacks
oblivious to the function being called — you don’t need to cast an Object to
something more specific, and you don’t need to create a new class to hold multiple
variables that you’d like to pass into the callback function.
Method 2 comes into it’s own when it’s used together with polymorphism, inheritance
and initialization patterns such as the factory pattern: if the work done by the
requesting and callback methods can be divided into smaller methods, a hierarchy of
asynchronous functions or commands can reuse code efficiently.
3. Closures
In both C# and Java, it’s possible for a method defined inside a method to have
access to variables in the enclosing method. In C# this is a matter of creating an
anonymous delegate, while in Java it’s necessary to create an anonymous class.
Using closures results in the shortest code, if not the most understandable code. In
some cases, execution proceeds in a straight downward line through the code —
much like a synchronous version of the code. However, people sometimes get
confused the indentation, and, more seriously, parameters after the closure definition
and code that runs immediately after the request is fired end up in an awkward place
(after the definition of the callback function.)
public class HttpGet : IAsyncFunction<String>
{
private Uri Path;
public HttpGet(Uri path)
{
Path = path;
}
public void Execute(CallbackFunction<String> outerCallback)
{
OuterCallback = outerCallback;
try
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(Path);
Request.Method = "GET";
Request.BeginGetRequestStream(delegate(IAsyncResult result) {
try {
response = request.EndGetResponse(result);
TextReader reader = new
StreamReader(response.GetResponseStream());
outerCallback(CallbackReturnValue<String>.CreateOk(reader.ReadToEnd()));
} catch(Exception ex) {
outerCallback(CallbackReturnValue<String>.CreateError(ex));
}
},null); // <--- note parameter value after delegate definition
}
catch (Exception ex)
{
outerCallback(CallbackReturnValue<String>.CreateError(ex));
}
}
}
The details are different in C# and Java: anonymous classes in Java can access local,
static and instance variables from the enclosing context that are declared final — this
makes it impossible for variables to be stomped on while an asynchronous request is
in flight. C# closures, on the other hand, can access only local variables: most of the
time this prevents asynchronous requests from interfering with one another, unless a
single method fires multiple asynchronous requests, in which case counter-intuitive
things can happen.
Conclusion
In addition to receiving return value(s), callback functions need to know something
about the context they run in: to write reliable applications, you need to be conscious
of where this information is; better yet, a strategy for where you’re going to put it.
Closures, created with anonymous delegates (C#) or classes (Java) produce the
shortest code, but not necessarily the clearest. Passing context in an argument to the
callback function requires the cooperation of the called function, but it makes few
demands on the calling and callback functions: the calling and callback functions can
both be static. When a single object contains both calling and callback functions,
context can be shared in a straightforward and typesafe manner; and when the calling
and callback functions can be broken into smaller functions, opportunities for efficient
code reuse abound.
http://gen5.info/q/2008/06/02/keeping-track-of-state-in-asynchronous-callbacks/[1/12/2014 9:30:30 PM]
4. Generation 5 » Keeping Track Of State In Asynchronous Callbacks
Paul Houle on June 2nd 2008 in Asynchronous Communications, Dot Net, GWT,
Java, Silverlight
Comments (6)
Comments (6)
Login
Sort by: Date Rating Last Activity
Thomas Hansen · 292 weeks ago
+1
Or you could use an Ajax Framework that queues up the requests which is the only sane thing to do
when you have a server/client solution and waits for the previous one to finish before creating a new
one ;)
(Hint; follow my link)
Nice blog though, and VERY important to be aware of, though probably less than 1% of ASP.NET AJAX
developers are... :)
Reply
admin · 292 weeks ago
0
@Thomas, your solution is a correct way to use AJAX and makes a lot of sense.
There is one case where it does make sense to generate concurrent requests, and that's when
information from several requests is going to be combined. Running requests in parallel can greatly
reduce the effects of latency -- in many cases this can make a large difference in performance (much
more than two.)
I think most people doing AJAX in Javascript can get away with being ignorant about concurrency
problems because they're bolting simple behaviors onto an HTML page: when something does go
wrong, the situation is usually recoverable. I know that I programmed a little AJAX here and there for
years and never experienced concurrency problems -- then I built a GWT app!
People working with tools like Silverlight, GWT and Flex (as well as a few brave Javascript Ninjas) are
building larger applications that are going to have more problems. It's time to spread the word about
the problems and the solutions!
Reply
Thomas Hansen · 292 weeks ago
0
@admin
Yes I totally agree, in fact I by "chance" stumbled into the problem when adding up a timer onto my
page and then frenetically clicked a button at the same time and by accident discovered that
sometimes the ViewState went completely *bananas* and the page became in an "undefined state"...
Then I spent more than a WEEK in fact re-creating our core to give support for sequential requests...
I think that yes you are right, there might exist some extreme scenarios where it makes sense to have
more than one running at the same time, though if they're both running towards the same server, you
will get OTHER problems (2 HTTP connections per IP constraint in most browsers)
So I think probably if you are going to use them you would normally have them first of all run towards
different IPs (servers) then also in addition it would be *WISE* to make sure they're not updating the
same parts of the UI...
Though for us (Gaia Ajax Widgets) this is completely abstract and would never happen unless people
completely mis-used our framework in ways it was never intended to be used for...
On the server creating more than one request towards OTHER servers (WebServices and so on)
asynchronously though is a totally different story...
.t
Reply
admin · 292 weeks ago
0
Well, in a perfect world, we'd design the client-server protocol so that all the information that the client
needs to handle a UI event comes in one big batch... Then you don't need to worry about
choreography, error handling and all those hairy issues. See this article.
In the real world we need to talk to server apps that we don't control... So we have to deal with those
issues.
http://gen5.info/q/2008/06/02/keeping-track-of-state-in-asynchronous-callbacks/[1/12/2014 9:30:30 PM]