Before starting to put AjaxPro.NET into action, let me give
you a brief introduction.
AjaxPro.NET
is a well-known open source framework, which is based on the server-side
techniques and provides support for constructing different versions of .NET Web
applications. The framework supports the server-side .NET SDK by a few means
via the client-side JavaScript. It can direct the JavaScript requests to the related
server-side .NET methods and then the server returns the newly-generated special
JavaScript to the browser. Its main functions are listed as below:
·
Access the Session and Application
data from the client-side JavaScript
·
Cache the required results
·
Freely use source code
·
Add and modify new methods and properties in the framework
without modifying any source code
·
All the classes support the client-side JavaScript to return
data, and DataSet can be used from inside the JavaScript
·
Use the HTML controls to access and return data
·
Do not need reload the pages and use the event delegate to access
data
·
Supply only one method for call and dramatically decrease the CPU
usage
Now, to use AjaxPro.NET in our ASP.NET 2.0 web applications
we should properly configure the web.config file. Since
the downloaded materials have been shipped with a guide and an excellent Visual
Studio Add-in—AjaxProVSTemplate.vsi, we will not talk
much about the usage of this framework, but focus on the main topic.
In this demo application we mainly provide three web pages—login.aspx, main.aspx, and chatroom.aspx. There is, however, a small trick worthy to
be mentioned first.
Index.html—a broker
To hide the browser's menu bar and toolbars in our chatting
pages, we use some tricks -building a temporary broker page index.html.
The client-side JavaScript in Listing 1 below shows the how-to.
Listing 1:
<body>
<script language = "javascript">
//open a new window
window.open("Login.aspx", "_blank",
"location=no;menubar=no;status=no;toolbar=no");
//close the parent window
Close();
// close the window without any prompt
function Close()
{
var ua = navigator.userAgent;
var ie = navigator.appName == "Microsoft Internet Explorer" ? true : false;
if (ie)
{
var IEversion = parseFloat(ua.substring(ua.indexOf("MSIE ") + 5, ua.indexOf
(";", ua.indexOf("MSIE "))))if (IEversion < 5.5)
{
var str = '<object id=noTipClose classid=
"clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">';
str += '<param name="Command" value="Close"></object>';
document.body.insertAdjacentHTML("beforeEnd", str);
document.all.noTipClose.Click();
}
else
{
window.opener = null;
window.close();
}
}
else
{
window.close()
}
}
</script>
</body>
Login.aspx
Next, comes up the normal login page, login.aspx, and Figure
3 shows you the first impress.
Figure 3
This web page is the entry point of this web-versioned
application, which merely calls the stored procedure UserLogin
described before so as to accomplish logging into the system. This procedure is
a typical one and we will not depict it, but only one thing should be noted: If
the user name entered is not empty and there is not an old one inside the
database, then we will simply store it whether its relevant password is empty
or not. For more details about this please check out the stored procedure's SQL
scripts. So next, we will move to the key code in the file login.aspx.cx.
Listing 2: The typical ASP.NET 2.0 server-side
database connection programming for the login page
public partial class login: System.Web.UI.Page
{
private string myConnectionString = ConfigurationManager.ConnectionStrings[
"msn_Data_ConnStr"].ConnectionString;
protected System.Data.SqlClient.SqlConnection sqlConnection;
protected System.Data.SqlClient.SqlCommand sqlCommand;
protected void Page_Load(object sender, EventArgs e){}
protected override void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.sqlConnection = new SqlConnection(myConnectionString);
this.sqlCommand = new System.Data.SqlClient.SqlCommand();
this.sqlCommand.CommandText = "dbo.[UserLogin]";
this.sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
this.sqlCommand.Connection = this.sqlConnection;
//specify the parameters of the stored procedure
this.sqlCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter(
"@RETURN_VALUE", System.Data.SqlDbType.Int, 4,
System.Data.ParameterDirection.ReturnValue, false, ((System.Byte)(0)), (
(System.Byte)(0)), "", System.Data.DataRowVersion.Current, null));
this.sqlCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter(
"@username", System.Data.SqlDbType.VarChar, 50));
this.sqlCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter(
"@password", System.Data.SqlDbType.VarChar, 50));
this.sqlCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter(
"@status", System.Data.SqlDbType.Int, 4));
}
protected void btnLogin_Click(object sender, EventArgs e)
{
int iRet = - 1;
sqlCommand.Parameters["@username"].Value = tbUsername.Text;
sqlCommand.Parameters["@password"].Value = tbPassword.Text;
sqlCommand.Parameters["@status"].Value = Convert.ToInt32
(ddlStatus.SelectedValue);
try
{
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
iRet = Convert.ToInt32(sqlCommand.Parameters["@RETURN_VALUE"].Value);
}
catch (SqlException)
{
Response.Write("<script>alert('Here,in SqlException');</script>");
//merely for debugging purpose
}
finally
{
sqlConnection.Close();
}
if (iRet == 0)
{
FormsAuthentication.RedirectFromLoginPage(tbUsername.Text, false);
Response.Redirect("Main.aspx");
}
if (iRet == 2)
{
FormsAuthentication.RedirectFromLoginPage(tbUsername.Text, false);
Response.Redirect("Main.aspx");
}
else
{
lblMessage.Text = "iRet =" + iRet.ToString() +
"The login failed, please check out your password!";
}
}
}
Main.aspx—the headquarters
Now, let us pay attention to the main controlling page of
the chatting system, main.aspx, whose run-time snapshot
is shown in Figure 4.
Figure 4
From the developer's point view, we can divide this part
into three different components: login status switching, the users list
viewing, and the newest message hinting. So, let us dig into their inner
workings one by one.
Switching between the login states
At the top of the main page lie the current user name and
its login status. It is easy for the user to switch between items Online and Offline via the ListBox control. When the user click the Logout
button, the user will log off and the control is switched to the initial login
page. Now, let us examine the related inner logic. First, we define an Ajax method—SetUserStatus on the server side, which directly
updates the user login status in table users
according to the passed arguments—strUsername and iStatus. Listing 3 gives the corresponding coding:
Listing 3
[AjaxPro.AjaxMethod]
public int SetUserStatus(string strUsername, int iStatus) {
//hold the returned value
int iRet = 0;
//Obtain the database connection string from the file web.config and set up the connection
string strConnection = ConfigurationManager.ConnectionStrings["msn_Data_ConnStr"].ConnectionString;
SqlConnection conn = new SqlConnection(strConnection);
//create a new SQLCommand object
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = string.Format(
"UPDATE users SET status = {0} WHERE username='{1}'",
iStatus, strUsername
);
try{
//open the data connection
conn.Open();
//execute the SQL command-- set the user's status
iRet = cmd.ExecuteNonQuery();
}
catch (SqlException){}
finally
{
//close the database connection
conn.Close();
}
return iRet;
}
Next comes up the relevant client-side function, setUserStatus, which will call the server-side method setUserStatus to update the current user login status, as
is shown in Listing 4.
Listing 4: The client-side JavaScript method calls
the server-side Ajax one
function setUserStatus()
{
//user name
var username = el("lblUsername").innerText;
//status
var status = el("user_status").value;
//call the relevant server-side Ajax method
AjaxProChat.SetUserStatus(username, status);
}
As for logoff, this is performed inside the button Logout-related event handler, lblExit_Click,
via the routine ASP.NET event response mechanism. Here we leave out the code
listing.
Viewing the user list
Note that, in this case, we take the action of inquiring the
database on time to list all the on-line users stuff. Therefore, we have to
earnestly count the cost between the user real-time characteristics and the
server-side load. Obviously, if the interval for inquiring the database is
shorter, then the real-time features of the application will be acceptable,
which will put a heavier burden on the server's shoulder. However, if the
interval is longer, then there is a lighter load on the server and the merciful
real-time characteristics on the client side. So, here we use some sleight: in
the database we add a sign—the field UsersChanged in
the table global_info which is used to record the
times table users to be changed. So, in the code we
can judge on time whether the sign has been changed to decide whether to send
requests to the server side for updating the on-line users list or not. Here,
for brevity, we select to omit the simple server-side code while making room for
the client-side programming.
Listing 5
//update the users list
function refreshUserlist()
{
//get the value of field UsersChanged from inside table users on the server side
var changed = AjaxProChat.StatusChanged().value;
//if table users has changed
if (changed > changedTimes)
{
//write down the current value of field UsersChanged
changedTimes = changed;
//obtain the DataTable object to hold the users info
var arUserlist = AjaxProChat.GetOnlineUserList().value.Tables[0];
//the <div> object to show the users list
var divUserlist = el("userlist");
//remove the old contents
while (divUserlist.childNodes.length > 0)
{
divUserlist.removeChild(divUserlist.childNodes[0]);
}
//show the users list
for (var i = 0; i < arUserlist.Rows.length; i++)
{
//the login user name
var username = arUserlist.Rows[i].username;
//nickname
var nickname = arUserlist.Rows[i].nickname;
//create a <div> object for showing one user message
var result = document.createElement("div");
//set the cursor shape hand-like
result.style.cursor = "pointer";
//inner patches
result.style.padding = "2px 0px 2px 0px";
//mouse click handler--open the chat room window
result.onclick = function()
{
//if the chat room window has not been opened
if (!sendWindow)
{
// open the chat room window--note the passed parameters
window.showModelessDialog("chatroom.aspx?username=" + username,
window, "help:no;unadorned:yes;edge:sunken;resizable:yes;status:no")
;
}
};
//the texts for the user name and the nickname are to be shown inside the <span> object
var result1 = document.createElement("span");
//set the mouse in-and-out effect
result1.onmouseover = function()
{
this.style.color = "#205288";
};
result1.onmouseout = function()
{
this.style.color = "#000000";
};
//set show style
result1.style.textAlign = "left";
result1.style.fontWeight = "bold";
result1.style.fontFamily = "Arial, Verdana";
//show the user name plus the nickname
result1.innerHTML = username + " (" + nickname + ")";
//attach the <div> object to DOM
result.appendChild(result1);
divUserlist.appendChild(result);
}
}
}
Since we have added so many comments on the import line, we
only sum up the general process: obtain the most recent users list inside the
database via the Ajax method—AjaxProChat.GetOnlineUserList();
fill in the user name and related nickname in turn. As is seen from above, we
use much subtle JavaScript programming around the DOM object—div
and span.
A MSN-like popping up window
To conveniently accept the new messages, we have designed a
small and friendly MSN-like hint window.
Figure 5: The run-time screenshot of the MSN-like
hint window
Page main.aspx is responsible for checking
on time whether there have been new messages coming in; if so, this small hint
window is to be popped up and the current user can click the link in it to
reply. As with the functions of the main page, there are also two steps—both
the server side and the client side—needed to accomplish such a prompt action.
First, we have defined an Ajax method, mainGetNewMessage,
who serves to obtain a DataSet of the newest chatting
messages. We can see the typical database connection in ASP.NET 2.0 from
Listing 6.
Listing 6: Code for the server-side method mainGetNewMessage
[AjaxPro.AjaxMethod]
public DataSet mainGetNewMessage()
{
DataSet ds = new DataSet();
SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings["msn_Data_ConnStr"].ConnectionString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = string.Format("GetNewMessage '{0}'", User.Identity.Name);
SqlDataAdapter da = new SqlDataAdapter(cmd);
try
{
da.Fill(ds);
}
catch (SqlException){}
finally
{
conn.Close();
}
return ds;
}
Since the code above is the common database operation and is
provided with so many notations, we will not give unnecessary details any more.
On the client side, there is accordingly defined a method, checkNewMessage, who is to invoke the server-side method, mainGetNewMessage, and will pop up a hint box whenever
there comes a new message. Listing 7 shows the related code snippet.
Listing 7: Code for the client-side method checkNewMessage
function checkNewMessage()
{
if (!sendWindow)
{
var dt = AjaxProChat.mainGetNewMessage().value.Tables[0];
if (dt.Rows.length > 0)
{
var sender = dt.Rows[0].sender;
var content = DealBrackets(dt.Rows[0].content);
var MSG1 = new CLASS_MSN_MESSAGE("aa", 200, 120, "Hint:", sender +
" says: ", content);
MSG1.oncommand = function()
{
if (!sendWindow)
{
window.showModelessDialog("chatroom.aspx?username=" + sender, window,
"help:no;unadorned:yes;edge:sunken;status:no");
}
};
MSG1.rect(null, null, null, screen.height - 50);
MSG1.speed = 10;
MSG1.step = 5;
MSG1.show();
}
}
}
Here shows the typical flow of calling an Ajax method on the
server side from within JavaScript on the client side. As you may have guessed,
the true secret for this hint window lies in the following code snippet.
Listing 8
var MSG1 = new CLASS_MSN_MESSAGE("aa",200,120,"Hint:",sender + " says: ",content);
Inside the downloadable source code, we define a pop up
window class in JavaScript in the file CLASS_MSN_MESSAGE.js.
We are creating an instance of the class CLASS_MSN_MESSAGE
and the last line above show the pop up window by calling the show method of the instance. For more details please do
research into the relevant JavaScript coding.
Chatroom.aspx
Lastly, we come to the meat and potatoes of this Ajax-based
chatting application. The really important window to start chatting is page chatroom.aspx. Let us first look at its run-time screenshot
in Figure 6.
Figure 6
As is seen from Figure 6, it is rather simple. Most of the
page is for chatting with friends and the corresponding messages, with a TEXTBOX control for entering the message to send and a basic Send button at the bottom line. You may have already guessed
the similar JavaScript programming skill is used for arranging the <div>
object and its inner sub items.
For easier comprehension, we have also divided the part into
three components: examining the recent messages, sending the messages,
and receiving the messages. Again, let us analyze them
one after the other.
Examining the recent messages
When the chat room window is loaded, there is a specified
number of latest chatting messages to be loaded. For this purpose, an AJAX method—GetRecentMsg is defined on the server side which
then invokes the stored procedure GetRecentMsg and
finally the required items of chat records return. Listing 9 gives the specific
coding of method GetRecentMsg.
Listing 9
[AjaxPro.AjaxMethod]
public DataSet GetRecentMsg(string strUsername)
{
DataSet ds = new DataSet();
SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings["msn_Data_ConnStr"].ConnectionString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = string.Format("GetRecentMsg '{0}','{1}', {2}",
User.Identity.Name, strUsername, 8);
SqlDataAdapter da = new SqlDataAdapter(cmd);
try
{
da.Fill(ds);
}
catch (SqlException){}
finally
{
conn.Close();
}
return ds;
}
Sending the messages
For this purpose, an AJAX method—SendMessage
is defined on the server side which then invokes the stored procedure GetRecentMsg and finally the required items of chat records
return. Listing 10 gives the specific coding of method GetRecentMsg.
Listing 10
[AjaxPro.AjaxMethod]
public DataSet GetRecentMsg(string strUsername)
{
DataSet ds = new DataSet();
SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings["msn_Data_ConnStr"].ConnectionString);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = string.Format("GetRecentMsg '{0}','{1}', {2}",
User.Identity.Name, strUsername, 8);
SqlDataAdapter da = new SqlDataAdapter(cmd);
try
{
da.Fill(ds);
}
catch (SqlException){}
finally
{
conn.Close();
}
return ds;
}
Receiving the messages
Here, certainly should we receive the messages in real time,
while the whole process is very much similar to that of the main page, so we do
not say more than is needed. But there is still one thing to be noticed, if the
chat room window has been open, the new message will be shown directly in it;
otherwise there will pop up a small hinting window (see Figure 5) for this new
message. This is why the global variable sendWindow is
defined inside page main.aspx's client-side
JavaScript, as is shown below.
Listing 11: The initial definition of the variable sendWindow
//……(omitted, inside main.aspx)
<script language="javascript">
//used to mark whether the chat room is open
var sendWindow = false;
//check out whether the user status has been changed
var changedTimes = 0;
//the main procedure
mainLoop();
//……
Although variable sendWindow is
defined inside page main.aspx for identifying whether
chat room has been already open, it is also used inside page chatroom.aspx. In connection with the definition above, in page
chatroom.aspx there exist the following code snippets.
Listing 12: Variable sendWindow
is also used in page chatroom.aspx
//……(omitted, inside page <span class=Italic>chatroom.aspx</span>)
<body onunload="dialogArguments.sendWindow=false;" onload="dialogArguments.sendWindow=true;">
//……
When page chatroom.aspx is opened
for the first time, variable sendWindow is set to true, when function checkNewMessage
in page main.aspx will not query new messages and the
message be displayed directly in the chat room. However, when the web page chatroom.aspx is close, variable sendWindow
is set to false, when function checkNewMessage in page main.aspx
will invoke the relevant method GetNewMessage in the
server side which will inquire new messages via the stored procedure GetNewMessage and finally show the result in the pop up
hinting box.
Author's Notes: until now, we have
introduced all the web pages and their rough functions in this sample. Due to
the strict demands of SQL Server 2005 Express Edition (and of course including
SQL Server 2005), I suggest you download and decompress the source code and
then configure the database engine with great care. As for the AjaxPro.NET
framework, maybe you are a newbie to it, but there is surely noy much
difficulty for you in grasping its general usage. Only one thing is to be
noticed—I use the latest version of AjaxPro.NET framework in this sample, but
it will be ok to follow me with the related schema. Last but not the least, I
have tested the demo project under hosted mode as well as under web mode using
Microsoft IE. That is all!