65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.68/5 (39投票s)

2009年3月9日

CPOL

2分钟阅读

viewsIcon

270176

downloadIcon

19649

使用 ASP.NET Ajax 构建一个类似于 GMail 的基于 Web 的聊天室,它可以处理多个请求和并发用户

SampleChat
使用该聊天室的对话截图

引言

我将向您展示如何使用 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 已改进
© . All rights reserved.