您的位置:首页 > 理论基础 > 计算机网络

在ASP.NET3.5下利用Linq,Ajax创建一个线上网络聊天室【转】

2008-10-14 19:15 736 查看
原文:Build a Web Chat Application using ASP.Net 3.5, LINQ and AJAX

英文水平有限,也不想用Google或者Yahoo或者其他翻译工具去逐句翻译,按俺自己的理解去写,希望不要偏离原文的意思(老天保佑~

)

创建一个线上聊天室,其实蛮好玩的,又用了感兴趣的Linq,所以才把这篇文章抄到这~



开发环境:ASP.Net 3.5, AJAX, JavaScript, C# 3.5, LINQ-to-SQL, MS SQL Server 2000/2005

聊天室的界面就是这个样子:



目标:

1)好玩,不好玩就不会做这个东东

2)聊天室不需要安装什么就可以登录聊天

3)页面无刷新

4)信息可以保存起来,下次登录还能看到聊天记录

5)使用Linq to Sql来代替存储过程,提高开发速度

6)聊天室不需要太复杂的功能,一个登录页,和一个聊天页就可以了,不想太复杂

好了,Go,GO!

1.在MS SQL Server 2000/2005上创建聊天室数据库,然后建一个聊天室的项目。数据库表结构及说明如下:



User: 包含用户的信息. 当然你还可以给User添加诸如 address, city, 获者其他一些字段.

Message: 记录用户的聊天信息.

Room: 记录聊天室信息. 一个用户可以进入不同的聊天室. 老外为了省事,下面的代码里,假定用户只有一个聊天室.

LoggedInUsers: 记录用户登录及聊天的一些信息。借助这个表,我们可以获得用户在一个指定的聊天室的一些信息.

2.打开VS2008,创建一个.NET Framework 3.5的ASP.NET网站。开发语言是:C#

3.建一个登录页,注册页以及登录用户和密码的加密就免了,Just for fun!不考虑那么多了。

4.创建聊天页,效果图及页面元素说明如下:



Div tag for Messages: 蓝色的Div Tag是聊天室的主要部分,显示聊天信息

TextBox: 输入你想说的话.

Send Button: 向聊天室发送你刚才输入的话.

Div tag for Chatters: 棕色的Div Tag是显示聊天室内的成员.

Log-out Button: 登出目前的聊天室.

Update Panel: VS2008已经集成了MS AJAX了,所以这个控件就不想说它在这起什么作用了.

Timer Control: 这个控件主要是为了更新聊天室的内容,每隔7秒刷新一次内容.
现在,界面上的完成了,该进入代码阶段了

首先关注下,整个聊天室的工作流程

1.首先,打开web.config,加入用户验证的东东


50         <authentication mode="Forms">

51             <forms name=".ASPXAUTH" loginUrl="Default.aspx"/>

52         </authentication>

53

54         <authorization>

55             <deny users="?" />

56         </authorization>


2.用户登录后由登录页跳转到聊天页时,用户名及密码用Session来保存。这里在跳转后,由于之前假定用户只有一个聊天室,

因此跳转后,会进入聊天室为"room1"的聊天页。如果存在多个聊天室,那么你可以再加一个聊天室的列表页,让用户进入到
这里,由他选择进入哪个聊天室。登录的代码如下:


13         protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)

14         {

15             LinqChatDataContext db = new LinqChatDataContext();

16

17             var user = (from u in db.Users

18                         where u.Username == Login1.UserName

19                         && u.Password == Login1.Password

20                         select u).SingleOrDefault();

21

22             if (user != null)

23             {

24                 e.Authenticated = true;

25                 Session["ChatUserID"] = user.UserID;

26                 Session["ChatUsername"] = user.Username;

27             }

28             else

29             {

30                 e.Authenticated = false;

31             }

32         }

33

34         protected void Login1_LoggedIn(object sender, EventArgs e)

35         {

36             Response.Redirect("Chatroom.aspx?roomId=1");

37         }


3.根据接收到的roomId的值,来确定聊天室的名字,已经聊天室的相关信息,比如成员,聊天记录等等


16                // for simplity's sake we're going to assume that a

17                 // roomId was passed in the query string and that

18                 // it is an integer

19                 // note: in reality you would check if the roomId is empty

20                 // and is an integer

21                string roomId = (string)Request["roomId"];

22                 lblRoomId.Text = roomId;


4.为了通知其他用户,该用户已进入聊天室,所以建立了LoggedInUser 来记录聊天室的一些信息。通过

这个表,我们可以获取聊天室的所有成员及信息。这个操作的代码如下:


26 this.InsertMessage(ConfigurationManager.AppSettings["ChatLoggedInText"] + " " + DateTime.Now.ToString());


5.InsertMessage的具体代码如下:


74         private void InsertMessage(string text)

75         {

76             LinqChatDataContext db = new LinqChatDataContext();

77

78             Message message = new Message();

79             message.RoomID = Convert.ToInt32(lblRoomId.Text);

80             message.UserID= Convert.ToInt32(Session["ChatUserID"]);

81

82             if (String.IsNullOrEmpty(text))

83             {

84                 message.Text = txtMessage.Text.Replace("<", "");

85                 message.Color = ddlColor.SelectedValue;

86             }

87             else

88             {

89                 message.Text = text;

90                 message.Color = "gray";

91             }

92

93             message.ToUserID = null;            // in the future, we will use this value for private messages

94             message.TimeStamp = DateTime.Now;

95             db.Messages.InsertOnSubmit(message);

96             db.SubmitChanges();

97         }


同时在web.config里加入以下代码:


24     <appSettings>

25         <add key="ChatLoggedInText" value="Just logged in!"/>

26     </appSettings>


6.完成了新增Message记录后,接下来是完成显示Message的功能了:


148         /// <summary>

149         /// Get the last 20 messages for this room

150         /// </summary>

151         private void GetMessages()
152         {

153             LinqChatDataContext db = new LinqChatDataContext();
154

155             var messages = (from m in db.Messages

156                            where m.RoomID == Convert.ToInt32(lblRoomId.Text)

157                            orderby m.TimeStamp descending

158                            select m).Take(20).OrderBy(m => m.TimeStamp);

159

160             if (messages != null)

161             {

162                 StringBuilder sb = new StringBuilder();

163                 int ctr = 0;    // toggle counter for alternating color

164

165                 foreach (var message in messages)

166                 {

167                     // alternate background color on messages

168                     if (ctr == 0)

169                     {

170                         sb.Append("<div style='padding: 10px;'>");

171                         ctr = 1;

172                     }

173                     else

174                     {

175                         sb.Append("<div style='background-color: #EFEFEF; padding: 10px;'>");

176                         ctr = 0;

177                     }

178

179                     if (message.User.Sex.ToString().ToLower() == "m")

180                         sb.Append("<img src='Images/manIcon.gif' style='vertical-align:middle' alt=''>  " + message.Text + "</div>");

181                     else

182                         sb.Append("<img src='Images/womanIcon.gif' style='vertical-align:middle' alt=''>  " + message.Text + "</div>");

183                 }

184

185                 litMessages.Text = sb.ToString();

186             }

187         }


7.当用户登录该聊天室时,右侧的用户列表区必须显示当前聊天室参与的的用户。当你选择某位用户时,你可以和他私聊。


99         private void GetLoggedInUsers()

100         {

101             LinqChatDataContext db = new LinqChatDataContext();

102

103             // let's check if this authenticated user exist in the

104             // LoggedInUser table (means user is logged-in to this room)

105             var user = (from u in db.LoggedInUsers

106                         where u.UserID == Convert.ToInt32(Session["ChatUserID"])

107                         && u.RoomID == Convert.ToInt32(lblRoomId.Text)

108                         select u).SingleOrDefault();

109

110             // if user does not exist in the LoggedInUser table

111             // then let's add/insert the user to the table

112             if (user == null)

113             {

114                 LoggedInUser loggedInUser = new LoggedInUser();

115                 loggedInUser.UserID = Convert.ToInt32(Session["ChatUserID"]);

116                 loggedInUser.RoomID = Convert.ToInt32(lblRoomId.Text);

117                 db.LoggedInUsers.InsertOnSubmit(loggedInUser);

118                 db.SubmitChanges();

119             }

120

121             string userIcon;

122             StringBuilder sb = new StringBuilder();

123

124             // get all logged in users to this room

125             var loggedInUsers = from l in db.LoggedInUsers

126                                 where l.RoomID == Convert.ToInt32(lblRoomId.Text)

127                                 select l;

128

129             // list all logged in chat users in the user list

130             foreach (var loggedInUser in loggedInUsers)

131             {

132                 // show user icon based on sex

133                 if (loggedInUser.User.Sex.ToString().ToLower() == "m")

134                     userIcon = "<img src='Images/manIcon.gif' style='vertical-align:middle' alt=''>  ";

135                 else

136                     userIcon = "<img src='Images/womanIcon.gif' style='vertical-align:middle' alt=''>  ";

137

138                 if (loggedInUser.User.Username != (string)Session["ChatUsername"])

139                         sb.Append(userIcon + "<a href=#>" + loggedInUser.User.Username + "</a><br>");

140                 else

141                     sb.Append(userIcon + "<b>" + loggedInUser.User.Username + "</b><br>");

142             }

143

144             // holds the names of the users shown in the chatroom

145             litUsers.Text = sb.ToString();

146         }


8.完成上叙代码,现在当你进入聊天室后,系统会把你进入聊天室的消息通知给该聊天室的当前用户。

接着,就是发送聊天信息:



上文提到用Textbox来输入聊天信息,要控制每次发送消息后,光标位置都在TextBox上,需要在两个位置进行控制,代码如下:

按钮"Send"点击事件:

58 ScriptManager1.SetFocus(txtMessage.ClientID);


另外还有Timer控件的监听事件:

   68 ScriptManager1.SetFocus(txtMessage);


当然,有时候你并不会去点击按钮来发送消息,而是直接敲击键盘的回车键(Enter),那么这个时候你要保持光标定位在TextBox上,怎么办呢?代码如下:

<form id="form1" defaultbutton="btnSend" defaultfocus="txtMessage" runat="server" >

当你发送一条消息,需要考虑一些问题,列表如下

聊天消息是如何被记录到当前聊天信息区域的.

如何获取已发送的消息.

用户的性别及消息怎样可以一并显示在聊天信息区域.

其他用户是如何接收到你的状态及消息的.

用户可以查看当前参与的用户(显示除自己以外,所有该聊天室的成员). 为了便于私聊,每个用户是带链接的,点击选择该用户可以进入私聊窗口,但是目前这不是我们考虑,预计在下一个例子里我们会实现该功能.



由于聊天消息不断增多,所以在聊天信息区域引入滚动条,并控制滚动条始终听聊在该区域的底部,代码如下:

首先是body:

<body style="background-color: gainsboro;" onload="SetScrollPosition()" onunload="LogMeOut()">

控制代码:

function SetScrollPosition()

{

var div = document.getElementById('divMessages');

div.scrollTop = 100000000000;

}

登出聊天室:

想退出聊天室,要么点退出按钮,要么直接关了浏览器,^_^

点退出按钮: 当用户点击退出时,首先从LoggedInUser将该用户删除,然后向聊天消息区域发送信息通知其他用户,该用户下线。

  189         protected void BtnLogOut_Click(object sender, EventArgs e)

  190         {

  191             // log out the user by deleting from the LoggedInUser table

  192             LinqChatDataContext db = new LinqChatDataContext();

  193 

  194             var loggedInUser = (from l in db.LoggedInUsers

  195                                where l.UserID == Convert.ToInt32(Session["ChatUserID"])

  196                                && l.RoomID == Convert.ToInt32(lblRoomId.Text)

  197                                select l).SingleOrDefault();

  198 

  199             db.LoggedInUsers.DeleteOnSubmit(loggedInUser);

  200             db.SubmitChanges();

  201 

  202             // insert a message that this user has logged out

  203             this.InsertMessage("Just logged out! " + DateTime.Now.ToString());

  204 

  205             // clean the session

  206             Session.RemoveAll();

  207             Session.Abandon();

  208 

  209             // redirect the user to the login page

  210             Response.Redirect("Default.aspx");

  211         }


关闭浏览器: 大多数用户可能不会老实的点退出按钮,而是直接叉掉这个浏览器窗口. 我们可以在客户端捕捉到这个事件, 只需要一点html代码和JavaScript脚本就ok了,代码如下

<body style="background-color: gainsboro;" onload="SetScrollPosition()" onunload="LogMeOut()">

JavaScript脚本:

function LogMeOut()

{

LogOutUserCallBack();

}

当然,我们还可以从服务端捕捉该事件,从LoggedInUser 删除该用户信息,利用ICallbackEventHandler接口,异步完成该操作

    8    public partial class Chatroom : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler


利用ICallbackEventHandler提供的方法完成以下两步操作. "RaiseCallbackEvent" 用于处理以控件为目标的回调事件. 下面是利用该方法,删除用户的LoggedInUsers表的信息.

  220         void  System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)

  221         {

  222             _callBackStatus = "failed";

  223 

  224             // log out the user by deleting from the LoggedInUser table

  225             LinqChatDataContext db = new LinqChatDataContext();

  226 

  227             var loggedInUser = (from l in db.LoggedInUsers

  228                                 where l.UserID == Convert.ToInt32(Session["ChatUserID"])

  229                                 && l.RoomID == Convert.ToInt32(lblRoomId.Text)

  230                                 select l).SingleOrDefault();

  231 

  232             db.LoggedInUsers.DeleteOnSubmit(loggedInUser);

  233             db.SubmitChanges();

  234 

  235             // insert a message that this user has logged out

  236             this.InsertMessage("Just logged out! " + DateTime.Now.ToString());

  237 

  238             _callBackStatus = "success";

  239         }


"GetCallbackResult" 用于获取返回以控件为目标的回调事件的结果. 我们可以声明一个变量来获取该方法返回的处理结果,这里我们对变量赋予"success" 或 "failed" 来标明当前事件的处理结果. 代码如下:

  215         string  System.Web.UI.ICallbackEventHandler.GetCallbackResult()

  216         {

  217             return _callBackStatus;

  218         }


接下来,我们在Page_Load方法里注册一个脚本事件,以完成这个异步的事件处理.

   29                 // create a call back reference so we can log-out user when user closes the browser

   30                 string callBackReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "LogOutUser", "");

   31                 string logOutUserCallBackScript = "function LogOutUserCallBack(arg, context) { " + callBackReference + "; }";

   32                 Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "LogOutUserCallBack", logOutUserCallBackScript, true);


结语:

老外的文章还是不怎么好翻译,要保证翻译后的文章达到信,达,雅这个高度太难了。不过因为好玩把这篇文章坚持看完,收获还是不小。原文最后还有一些话没翻译,如果想看,点击本文开头就可以找到原文。我就偷下懒了~


代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: