Timing and Ordering Ajax Calls to the Server ASP.NET

Browsers will always make a maximum of two concurrent Ajax calls to a domain.If five Ajax calls are made,the browser will first make two calls and queue the remaining three calls,wait for either one of them to complete, and then make another call until all queued calls are complete.However, the calls will not execute in the same order as you make them (see Figure ).

The browser makes two calls at a time to the server, so the smaller but later calls might finish before the larger calls that are made first

Timing and Ordering Ajax Calls to the Server

As Figure shows,the third call is large and takes longer than the fifth call to download.So, the fourth and fifth calls are actually executed before the third call finishes.

Bad Calls Make Good Calls Time Out

If two HTTP calls some how get stuck for too long,they will make some good queued calls time out too (see Example ).

Testing bad calls that make good calls time out

Testing bad calls that make good calls time out (continued)

Example calls a TestService, which is a web service with two methods:Hello World and Time out. The idea is to find out which calls time out by hooking onto the web service’s default fail handler. If a call fails, that fail handler will be fired.The web service’s code is simple, as shown in Example

The test web service calls timeout

Example calls the Timeout method on the server, which does nothing but wait until the call is timed out.After that, you call a method that does not time out. Figure shows the output.

Testing the Ajax call timeout

Testing the Ajax call timeout

Only the first call succeeded.So, if the browser’s two connections get jammed, then other waiting calls will time out too.

Testing the Ajax call timeout

Problem: Bad web service calls get stuck causing excessive timeout errors.

Solution: Modify the ASP.NET AJAX runtime and introduce automatic retry.

At one community web portal company I worked at, we used to get 400 to 600 time out error reports from users’browsers.We first suspected a slow Internet connection,but that couldn’t happen for so many users. We then thought something was wrong with the hosting provider’s network and did a lot of network analysis to find any problems on the network but there weren’t.We used SQL Profiler to see if there were any long-running queries that timed out the ASP.NET request execution time, but that wasn’t it either.

We finally discovered that it mostly happened when some bad web service calls got stuck and made the good calls time out while waiting in the browser’s “maximum of two calls at a time” queue. So, we modified the ASP.NET AJAX runtime and introduced automatic retry on it.The problem disappeared almost completely.However,this auto retry requires sophisticated open-heart surgery on the ASP.NET AJAX Frame work itself. The idea is to make each and every call retry once when it times out.To do that, we need to intercept all web method calls and implement a hook on the on Failed call back, which called the same web method again if the failure reason was a time out.

Common problems

Sometimes the first web service call gets an intermediate page or an invalid HTTP status instead of the expected result so the first call fails.Retrying it solves the problem.

Another common problem is wireless Inter net users and slow Internet users. Wireless connections drop ran domly and some times wireless access points get stuck.And dial-up connection drops have an automated redial sequence.All these problems can make Ajax calls wait for too long and they eventually time out or fail.We can prevent a majority of these problems with an auto retry mechanism in place.

In the ASP.NET AJAX Framework,the Sys$ Net$Web Service Proxy$ invoke function is responsible for making all web service calls. So,we replace this function with a custom implementation that passes a custom on Failure callback.That custom callback gets fired whenever there’s an error or timeout.

When there’s a time out, it calls the invoke function again and thus a retry happens.Example shows the code block that replaces the ASP.NET AJAX Framework’s invoke function adds the auto retry capability to it.

You do not need to open the Ajax run time Java Script files and modify the implementation— just put this block of Java Script inside a < SCRIPT> tag on your page after the Ajax scripts down load. It adds a retry capability on top of the original invoke function and eventually calls the original invoke function.

It also does not break when newer version of the ASP.NET AJAX Frame work is released.As long as Micro soft does not completely change the invoke function, it is safe to add this patch.

Implementing the auto retry at failure

Implementing the auto retry at failure(continued)

Auto retry test

Auto retry test

The first method succeeded, and all the others timed out and were retried. Although you see them time out again because the Test Service always times out, that won’t happen in a real-world implementation because the second attempt will not time out unless there’s a real problem on this call that makes the server time out on every attempt.

Browsers Fail to Respond with Two or More Calls in Queue

Try this: go to any Start page that loads many RSS feeds or wid gets on the first visit.While the page is loading,try clicking on a link that takes you to another web site, or try visiting another site by entering a URL on the browser address bar.

The browser is stuck.Until all queued Ajax calls in the browser complete,the browser will not accept any other request.All browsers have this problem, but this problem is worse in Inter net Explorer.

As discussed earlier,the browser keeps all calls in a queue and executes a maximum two of them in parallel.The browser has to wait for running calls to complete before it can take another call.

The solution to this problem is to prevent more than two calls to be queued in the browser at a time. The solution is tricky: maintain a queue yourself and send the calls to the browser’s queue from your own queue one at a time (see Example).

GlobalCallQueue prevents the browser from getting stuck

GlobalCallQueue prevents the browser from getting stuck (continued)

The Queued Call class encapsulates one web method call.It takes all the parameters of the actual web service call and overrides the onSuccess and onFailure callbacks.We want to know when a call completes or fails so that we can issue another call from our queue.

The GlobalCallQueue maintains a list of all web service calls that get into the queue.Whenever a web method is called, the call is queued in the Global Call Queue,and calls are executed from the queue one at a time.This ensures that the browser does not get more than two web service calls at a time, which means the browser doesn’t get stuck.

To enable the queue-based call, you have to override the ASP.NET AJAX web method invocation again, as done in the “Bad Calls Make Good Calls Time Out”section (see Example).

Override the default invoke function implementation and replace it with a queue implementation

The override in Example ensures that all web service calls get into the queue instead of executing immediately.The Globa lCall Queue takes care of making the call at the right time. And just like the previous auto retry implementation, this is an addon to the ASP.NET AJAX Frame work.When you upgrade the framework, you don’t need to change the Global Call Queue again as long as Microsoft does not change the invoke function approach completely.

Caching Web Service Responses on the Browser

You already know browsers can cache images,JavaScript,and CSS files on a user’s hard drive.They can also cache XML HTTP calls if the call is an HTTP GET and not an HTTP POST because the cache is based on the URL. If it’s the same URL and it’s cached on the computer, then the response is loaded from the cache, not from the server when it is requested again. Basically, the browser can cache any HTTP GET call and return cached data based on the URL.

you make an XML HTTP call as HTTP GET and the server returns a special header that informs the browser to cache the response,the response will be immediately returned from the cache on future calls and saves the delay of a network round trip and download time.Such client-side caching of XML HTTP can dramatically increase client-side performance as well as decrease server-side load.

You can also cache a user’s state so that when the same user visits again the following day,the user gets a cached page that loads instantly from the browser cache,not from the server.This makes the second time load very fast. Other small actions can also be cached, such as clicking on the Start button, which shows you a list of widgets.

When the user does the same action again, a cached result is loaded immediately from the local cache and thus saves the network roundtrip time.The user gets a responsive fast-loading site and the perceived speed increases dramatically.

The idea is to make HTTP GET calls while making ASP.NET AJAX web service calls and return some specific HTTP response headers that tell the browser to cache the response for some specified duration.If you return the Expires header during the response, the browser will cache the XML HTTP response.

There are two headers that you need to return with the response to instruct the browser to cache the response:

HTTP/1.1 200 OK
Expires: Fri, 1 Jan 2030
Cache-Control: public

This will instruct the browser to cache the responses until January 2030. As long a you make the same XML HTTP calls with the same parameters, you will get a cached response from the computer and no call will go to the server.

There are more advanced ways to gain further control over response caching. For example,here is a header that will instruct the browser to cache for 60 seconds and get a fresh response after 60 seconds from the server.

It will also prevent proxies from retu rning a cached response when the browser’s local cache expires after 60 seconds. You can learn more about caching strategies for performance improvement in Chapter.

HTTP/1.1 200 OK
Cache-Control:private, must-revalidate,proxy-revalidate, max-age=60

Example tries to produce such headers from the web service as per ASP.NET documentation.

Failed attempt to produce necessary response headers for caching on the client side

Incorrect HTTP response headers are generated from the web method when you try to produce the headers as documented

Incorrect HTTP response headers are generated from the web method

The Expires header is set properly, but the problem is with the Cache-Control header.It is showing that the max-age is set to zero, which will prevent the browser from doing any kind of caching.Looks like instead of caching the response, the exact opposite happened.The headers actually tell the browser to never cache the response, and always get fresh content from the server no matter what.

The output is incorrect and not cached. If you repeatedly call the web method, you will get a noncached response.Figure shows the output of the web method call where it always produces a distinct timestamp.This means the browser is making a call to the server every time and no caching occurs.

Continuous calls to the web method return unique timestamps, which means the call is not being cached and the browser is requesting the server all the time

Continuous calls to the web method return unique timestamps

There’s a bug in ASP.NET 2.0 that does not let you change the max-age header once it is set. Because the max-age is set to zero by the ASP.NET AJAX Framework by default, ASP.NET 2.0 sets the Cache-Control to private because max-age = 0 means “Prevent caching at any cost.” So, there’s no way you can make ASP.NET 2.0 return proper headers that cache the response.

Time for a hack. I found the code after decompiling the Http Cache Policy class’s code(Context.Response.Cache object’s class; see Figure ).

The decompiled code in the Http Cache Policy class in the ASP.NET 2.0 Framework that deals with the maxAge value

decompiled code in the Http Cache Policy class in the ASP.NET 2.0 Framework that deals with the maxAge value

From the ASP.NET AJAX Framework code, this._maxAge is being set to zero and if(...||(delta < this._maxAge))is preventing it from being set to a larger value.

We need to bypass the SetMaxAge function and set the value of the _maxAge field directly, using reflection (see Example).

Set _maxAge field’s value directly by bypassing the SetMaxAge function

The proper response headers for the cache

The proper response headers for the cache

Now max-age is set to 60,and the browser will cache the response for 60 seconds.If you make the same call again within 60 seconds, it will return the same response. Figure shows a test output that shows the date time returned from the server.

Cache successful

Cache successful

After one minute,the cache expires and the browser makes a call to the server again.The client-side code for this experiment is like this:

But there’s another problem to solve.In web.config, ASP.NET AJAX will add:

<system.web>
<trust level="Medium"/>

This prevents us from setting the _maxAge field of the Response object because it requires reflection,which requires full permission.So, you will have to change the trust level to Full:

<system.web>
<trust level="Full"/>

You can create an HTTP module that intercepts all web service calls and returns the proper cache header for HTTP GET calls,which will save you from writing the same code in many web methods.



Face Book Twitter Google Plus Instagram Youtube Linkedin Myspace Pinterest Soundcloud Wikipedia

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

ASP.NET Topics