使用 ASP.NET Ajax 构建一个基于 Web 的聊天室






4.68/5 (39投票s)
使用 ASP.NET Ajax 构建一个类似于 GMail 的基于 Web 的聊天室,它可以处理多个请求和并发用户

使用该聊天室的对话截图
引言
我将向您展示如何使用 ASP.NET 2.0/3.5、ScriptServices 和 SQL Server 数据库构建一个基于 Web 的聊天室,它可以处理多个请求和并发用户。
提供的源代码几乎可以准备好复制并粘贴到任何 3.5 Web 应用程序中。
要求
- 聊天应用程序必须是基于 HTTP 的。 不允许使用其他协议。
- 该应用程序必须允许多个聊天室。
- 用户可以离开房间,而无需通知应用程序。
- 房间中的聊天者列表必须反映最新的更改,延迟时间不超过(例如)5 秒。
- 消息列表的检索延迟时间不得超过(例如)2 秒。
应用程序状态
由于在 HTTP 中,连接在单个请求/响应对之后关闭,因此您必须模拟连接到聊天室的状态。 我通过拥有聊天用户的应用程序状态对象来实现这一点。 此外,由于您在用户断开连接时没有收到通知,因此您必须定期检查用户的最新活动,以便手动将其从聊天用户列表中删除。
public void ValidateUsers(TimeSpan maxInterval)
{
List<int> toDelete = new List<int>();
foreach (System.Collections.Generic.KeyValuePair<int> keyValue in this.Users)
{
//Identify which users don't have recent activity
if (DateTime.Now.Subtract(keyValue.Value.LastActivity) > maxInterval)
{
toDelete.Add(keyValue.Key);
}
}
//Remove them from the current users list
//...
}
启用 Ajax 的 Web 服务
Ajax 服务公开了四个方法
EnterRoom
:它通过将用户添加到房间用户列表,将用户分配到聊天室。CheckMessages
:它负责从数据库中获取最新消息并检查用户列表。SendMessage
:它保存消息并检查用户列表,返回最新消息。CheckUsers
:它通过获取用户的最新活动来验证聊天室中的所有用户列表,如果列表发生更改,则返回新的用户列表。
客户端脚本
客户端脚本负责使用setTimeout
对 Ajax 调用来刷新屏幕上的消息列表。
在这里,您可以看到向 Web 服务发出请求及其回调的 JavaScript。
Codeproject.Chat.EnterRoom = function()
{
//Calls the web service to enter the chat
SampleChat.Chat.Services.ChatService.EnterRoom(Codeproject.Chat.RoomId,
Codeproject.Chat.EnterRoomCallback);
}
//EnterRoom Callback
Codeproject.Chat.EnterRoomCallback = function(lastMessageId)
{
//Store the last message id in a JavaScript global variable
Codeproject.Chat.LastMessageId = lastMessageId;
//Remove the loading message
Codeproject.Chat.MessagePanel.className = "";
//Get the users list
Codeproject.Chat.CheckUsers();
//Get the messages list
Codeproject.Chat.CheckMessages();
}
//Updates the users list
Codeproject.Chat.CheckUsers = function ()
{
//Check and validate users in the webservice
SampleChat.Chat.Services.ChatService.CheckUsers(Codeproject.Chat.CheckUsersCallback);
//Timer to check users
setTimeout(Codeproject.Chat.CheckUsers, Codeproject.Chat.CheckUsersRefresh);
}
Codeproject.Chat.CheckUsersCallback = function(response)
{
if (response.Users.length > 0)
{
Codeproject.Chat.ArrangeUsers(response.Users);
}
}
Codeproject.Chat.CheckMessages = function ()
{
//Calls the web service to check for new messages
SampleChat.Chat.Services.ChatService.CheckMessages(Codeproject.Chat.LastMessageId,
Codeproject.Chat.CheckMessagesCallback);
//Set the timer to check the messages next time.
setTimeout(Codeproject.Chat.CheckMessages, Codeproject.Chat.CheckMessagesRefresh);
}
Codeproject.Chat.CheckMessagesCallback = function(response)
{
if (response.Messages.length > 0)
{
//Store the last message id
Codeproject.Chat.LastMessageId = response.LastMessageId
//Show the latest message in the message list
Codeproject.Chat.ArrangeMessages(response.Messages);
}
if (response.Users.length > 0)
{
//Show the latest message in the message list
Codeproject.Chat.ArrangeUsers(response.Users);
}
}
Codeproject.Chat.SendMessage = function ()
{
var message = Codeproject.Chat.MessageTextbox.value;
if (message.trim() != "")
{
SampleChat.Chat.Services.ChatService.SendMessage(message,
Codeproject.Chat.LastMessageId,
Codeproject.Chat.CheckMessagesCallback);
Codeproject.Chat.MessageTextbox.focus();
Codeproject.Chat.MessageTextbox.value = "";
}
}
运行聊天室所需的所有客户端脚本都在命名空间Codeproject.Chat
下的源代码中提供。
数据库
这是聊天室使用的数据库表的设计。
由于记录的数量在几个小时/几天内可能会大量增长,因此通过其聚集索引查询此表非常重要,仅获取自您检索到的上一条消息以来的新消息(将检索到的最后一条消息的Id
存储在用户状态中)。
CREATE TABLE [dbo].[ChatMessages](
[MessageId] [int] IDENTITY(1,1) NOT NULL,
[RoomId] [int] NOT NULL,
[MessageBody] [varchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[MessageDate] [datetime] NOT NULL,
[UserId] [int] NOT NULL,
[IsSystem] [bit] NOT NULL,
CONSTRAINT [PK_ChatMessages] PRIMARY KEY CLUSTERED
(
[MessageId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
希望您喜欢它!
历史
- 2009 年 3 月 2 日 - 文章已提交
- 2009 年 3 月 9 日 - 文章正文已扩展
- 2010 年 2 月 24 日 - JS 已改进