![]() |
Web Development »
ASP.NET »
Howto
Intermediate
License: The Code Project Open License (CPOL)
Using the XMLHTTP object to synchronise pages in ASP.NETBy Allan EagleHow to use the XMLHTTP object to synchronise pages in ASP.NET. |
C# (C# 1.0, C# 2.0, C# 3.0), Javascript, ASP.NET, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

Imagine the scenario where you have multiple users viewing a page in your web application. You want to have each client page updated automatically when there are changes to the data the page is displaying.
Because of the request/response nature of web applications, we can not simply get our application to communicate directly to clients that are viewing our page and tell them to update their content as with a traditional client/server application. This article explores a way to synchronise your user's views using the XMLHTTP handler.
If we use the META tag in the header of our ASP.NET page, we could get a page to reload every few seconds, showing updated content since the last reload. So, what is wrong with doing this?
In a situation where we have a 100 users viewing a page with our META tag set to reload the page every 5 seconds, each page would generate a request for an ASP.NET page, which in turn might be querying a database. That is a lot of page requests, doing a lot of work, which is mainly unnecessary seeing that the data is unlikely to be changing every 5 seconds.
We need a way for a client to ask our application if it is necessary to update its content ... We can do this using the XMLHTTP object.
There are four main components of the demonstration web application which are used to synchronise the ASP.NET page in our demo web app.
A controller class representing the bowels of the application (our business layer, if you like ...).
Our ASP.NET page displaying data we want synchronized across multiple client sessions. This contains a GridView control displaying products with functions to add, edit, and remove products.
JavaScript code using the XMLHTTP object to perform 'behind the scenes' requests to CheckSync.ashx. This is included in the Default.aspx page.
An HTTP handler with a simple job of responding to an XMLHTTP request, with a flag determining if a page should update its content.
To achieve our page synchronization, we are going to keep two references. One reference is going to be kept with the client (in the session state), and the other is going to be kept with the server (in the application state).
When any action takes place such as adding, editing, or deleting, the server will increment its reference. The client will regularly check its reference against the server reference. If the server reference is higher, the client will synchronize its content and copy the server reference to its own. This process repeats until the client is no longer viewing the data.
I have built a set of classes to accommodate simple synchronization in the demo.

ViewSynchronisationResponsible for creating a server reference and ensuring that only one copy exists in the application.
ServerSynchronisationReferenceHolds a server synchronization reference.
ClientSynchronisationReferenceHolds a client synchronization reference.
The process of the client checking its reference against the server is detailed below.
DemoWebAppCore is instantiated in the Application_Start() method of Global.asax.protected void Application_Start(object sender, EventArgs e)
{
...
Application["Engine"] = new DemoWebAppCore();
...
}
DemoWebAppCore.ProductViewSync is instantiated.public class DemoWebAppCore
{
...
private ViewSynchronisation _productViewSync =
new ViewSynchronisation("Products");
public ViewSynchronisation ProductViewSync
{ get { return _productViewSync; } }
...
}
Session["ClientSyncRef"] is instantiated with a ClientSynchronisationReference using DemoWebAppCore.ProductViewSync.CreateClientReference() in the Session_Start() method of Global.asax.protected void Session_Start(object sender, EventArgs e)
{
Session["ClientSyncRef"] =
Engine.ProductViewSync.CreateClientReference();
}
XMLHTTP request for SyncCheck.ashx.var pollInterval = 5000;
var checkStatusUrl = "CheckSync.ashx";
var pollID = window.setInterval(checkStatus, pollInterval);
function checkStatus()
{
// create XMLHTTP object
req = createReq();
if(req != null)
{
req.onreadystatechange = process;
req.open("GET", checkStatusUrl, true);
req.send(null);
}
else
window.removeInterval(pollID);
}
function createReq()
{
// Create XMLHTTP compatible in various browsers
try
{
req = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e)
{
try
{
req = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(oc)
{
req = null;
}
}
if (!req && typeof XMLHttpRequest != "undefined")
{
req = new XMLHttpRequest();
}
return req;
}
ClientSynchronisationReference in Session["ClientSyncRef"] is invalid using ClientSynchronisationReference.IsInvalid. If it is, CheckSync.ashx returns the character "1" in its response. Otherwise, it will return "0".public void ProcessRequest(HttpContext context)
{
// Make sure that the response of this
// handler is not cached by the browser
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.ContentType = "text/plain";
if (ClientSyncRef(context) != null)
{
if (ClientSyncRef(context).IsInvalid)
{
// Client ref was invalid so ...
// return 1 to CheckSync.js
context.Response.Write("1");
return;
}
}
// Client ref was not invalid so return 0 to CheckSync.js
context.Response.Write("0");
}
function process()
{
// simply determine response from CheckSync.ashx
// and refresh current window if 1 is returned
if (req.readyState == 4 && req.status == 200 &&
req.responseText == '1')
window.location.replace(window.location.href);
}
As mentioned previously, whenever data changes, we need to invalidate our client views. To do this, we simply call the ViewSynchronisation.InvalidateClients() method.
public void AddProduct()
{
...
ProductViewSync.InvalidateClients();
}
public void UpdateProduct(long Id, string Name,
string Description, decimal Price)
{
...
ProductViewSync.InvalidateClients();
}
public void RemoveProduct(long Id)
{
...
ProductViewSync.InvalidateClients();
}
By calling InvalidateClients(), we are simply incrementing the reference stored in ServerSynchronisationReference._syncRef.
public void InvalidateClients()
{
Interlocked.Increment(ref _syncRef);
}
So, when a client checks ClientSynchronisationReference.IsInvalid, a simple comparison is made of its own client reference and the server reference.
public bool IsInvalid
{
get
{
long _serverSyncRef = _serverRef.Value;
// If server sync ref is greater than the client,
// then client is invalid
if (_serverSyncRef > _clientSyncRef)
{
_clientSyncRef = _serverSyncRef;
return true;
}
return false;
}
}
XMLHTTP and an ASHX handler, we cut out most of the overheads involved with a full postback to an ASPX page. Also, we cut out the annoyance of full page refresh at the browser side.var pollInterval line in the CheckSync.js file.XMLHTTP request to pull down modified data and update the page dynamically for a totally transparent update.Remember also, CheckSync.ashx doesn't only have to return "1" and "0" ...
Server reference = 1
Product 234 added
Server reference = 2
Product 634 updated
Server reference = 3
Product 231 removed
| You must Sign In to use this message board. | |||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 17 Feb 2008 Editor: Smitha Vijayan |
Copyright 2008 by Allan Eagle Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |