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

ASP.NET MVC 5:使用 jQuery 和 AJAX 实现 ShoutBox 功能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (5投票s)

2016年12月2日

CPOL

5分钟阅读

viewsIcon

21940

downloadIcon

671

本文将指导您在 ASP.NET MVC 5 应用程序中实现一个简单的“shoutbox”功能。

引言

本文将指导您在 ASP.NET MVC 5 应用程序中实现一个简单的“shoutbox”功能。我称之为“shoutbox”,因为您网站内的用户可以相互交流。您可以将其视为一个评论板,或者非常类似于一个群聊窗口。请注意,“shoutbox”并不是一个功能完善的聊天功能实现。如果您正在寻找一个聊天应用程序,可以参考我关于 使用 ASP.NET SignalR 构建简单实时聊天应用程序 的另一篇文章。

背景

实现此功能有多种可能的方法,但由于本文档的目标读者是初学者到中级开发人员,我决定使用一种简单而典型的方式,即使用 jQuery 和 AJAX 执行异步操作。如果您想要一个简单干净的 API,允许您创建需要服务器持续将数据推送到客户端/浏览器的实时 Web 应用程序,那么您可能需要查看 ASP.NET SignalR 。

在继续之前,请确保您对 ASP.NET MVC 及其在 MVC 架构中的工作原理有基本了解,因为本文档不会涵盖这些内容。我建议您阅读我之前关于“使用 Entity Framework 和 MVC 5 构建 Web 应用程序”的文章,因为我在该应用程序中集成了此功能。如果您还没有阅读我之前的文章,可以参考下面的链接:

让我们开始吧!

引用

可下载的源代码**不**包含本文档中提到的代码。您需要做的就是按照本文档中提到的步骤进行操作,并将其集成到现有的可下载代码中。我之所以这样做,是为了让您了解在哪里以及哪个文件会受到影响以集成此功能,而不是直接运行代码。

第一步

我们首先需要做的是在数据库中创建一个新表来存储每个用户的消息。现在,启动 SQL Server Management Studio,运行下面的 SQL 脚本创建一个 Message 表:

<code>CREATE TABLE [dbo].[Message](  
    [MessageID] [int] IDENTITY(1,1) NOT NULL,
    [SYSUserID] [int] NULL,
    [MessageText] [varchar](max) NULL,
    [DatePosted] [datetime] NULL,
CONSTRAINT [PK_Message] PRIMARY KEY CLUSTERED  
(
    [MessageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO</code>

第二步

之后,切换回 Visual Studio,然后通过转到 Models 文件夹 > DB > DemoModel.edmx 打开您的 EF 设计器。

右键单击设计器表面,然后选择“从数据库更新模型”。选择 Message 表将其添加到我们的实体集中,然后单击完成,如下图所示:

第三步

在 Models 文件夹 > ViewModel > UserModel.cs 下添加以下类:

<code>public class UserMessage  
{
    public int MessageID { get; set; }
    public int SYSUserID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string MessageText { get; set; }
    public DateTime? LogDate { get; set; }
}</code>

上面的代码只是一个简单的类,它包含一些属性来存储来自数据库的数据。

第四步

在 Models 文件夹 > ObjectManager > UserManager.cs 下添加以下代码块:

<code>public List<UserMessage> GetAllMessages() {  
    using (DemoDBEntities db = new DemoDBEntities()) {
        var m = (from q in db.SYSUsers
                    join q2 in db.Messages on q.SYSUserID equals q2.SYSUserID
                    join q3 in db.SYSUserProfiles on q.SYSUserID equals q3.SYSUserID
                    select new UserMessage {
                        MessageID = q2.MessageID,
                        SYSUserID = q.SYSUserID,
                        FirstName = q3.FirstName,
                        LastName = q3.LastName,
                        MessageText = q2.MessageText,
                        LogDate = q2.DatePosted
                    }).OrderBy(o => o.LogDate);

        return m.ToList();
    }
}

public void AddMessage(int userID, string messageText) {  
    using (DemoDBEntities db = new DemoDBEntities()) {
        Message m = new Message();
        m.MessageText = messageText;
        m.SYSUserID = userID;
        m.DatePosted = DateTime.UtcNow;

        db.Messages.Add(m);
        db.SaveChanges();
    }
}

public int GetUserID(string loginName) {  
    using (DemoDBEntities db = new DemoDBEntities()) {
            return db.SYSUsers.Where(o => o.LoginName.Equals(loginName))
                              .SingleOrDefault().SYSUserID;
    }
}</code>

GetAllMessages() 方法从数据库中获取所有已存储的消息,并将每个字段的值赋给 UserMessage 模型相应的属性。AddMessage() 方法只是将新数据集添加到数据库。最后,GetUserID() 方法通过将登录名作为参数传递来获取当前登录用户的用户 ID。

第五步

在 Controllers 文件夹 > HomeController.cs 下添加以下操作方法:

<code>[Authorize]
public ActionResult Index()  
{
    UserManager UM = new UserManager();
    ViewBag.UserID = UM.GetUserID(User.Identity.Name);
    return View();
}

[Authorize]
public ActionResult ShoutBoxPartial() {  
    return PartialView();
}

[Authorize]
public ActionResult SendMessage(int userID, string message) {  
    UserManager UM = new UserManager();
    UM.AddMessage(userID, message);
    return Json(new { success = true });
}

[Authorize]
public ActionResult GetMessages() {  
    UserManager UM = new UserManager();
    return Json(UM.GetAllMessages(), JsonRequestBehavior.AllowGet);
}</code>

在 Index 操作方法中,我们通过将登录名作为参数传递来调用 GetUserID() 方法,以获取当前登录用户的用户 ID。然后,我们将该值存储在 ViewBag 中,以便稍后在我们的 View 中引用它。SendMessage() 操作方法只是调用 AddMessage() 方法将新记录插入数据库。GetMessages() 操作方法从数据库中获取所有用户消息。

第六步

在 Views 文件夹 > Home 下创建一个名为“ShoutBoxPartial.cshtml”的新部分视图,然后添加以下标记:

<code><style type="text/css">  
    #divShoutBox {position:relative; width:400px; height:300px; overflow:auto;}
    #txtMessageText {width:400px; height:100px;}
</style>

<div id="divShoutBox">  
    <div id="divUserMessage"></div>
</div>

<br />  
<textarea id="txtMessageText"></textarea>  
<br />  
<input type="button" id="btnPost" value="Post" />

<script>  
    var _isScrolling = false;
    var _lastScrollPos = 0;
    var _counter = 0;

    $(function () {

        GetMessages();
        setInterval(Fetch, 5000);

        $("#divShoutBox").on("scroll", function () {
            _isScrolling = true;
            _lastScrollPos = this.scrollHeight;
        });

        $("#btnPost").on("click", function () {
            var msg = $("#txtMessageText");
            var user = $("#hidUserID");

            if (msg.val().length > 0) {
                $.ajax({
                    type: "POST",
                    url: '@(Url.Action("SendMessage","Home"))',
                    data: { userID: user.val(), message: msg.val() },
                    success: function (d) { msg.val(""); GetMessages(); },
                    error: function (err) { }
                });
            }
        });

    });


    function Fetch() {
        if (!_isScrolling) {
            GetMessages();
            $("#divShoutBox").scrollTop(_lastScrollPos);
        };
        _isScrolling = false;
    }

    function GetMessages() {
        $.ajax({
            type: "POST",
            url: '@(Url.Action("GetMessages","Home"))',
               data: {},
               success: function (d) {
                   $("#divUserMessage").empty();
                   $.each(d, function (index, i) {
                       GenerateHTML(i.FirstName, i.LastName, i.MessageText, FormatDateString(i.LogDate));
                   });
               },
               error: function (err) { }
        });
    }

    function GenerateHTML(fName, lName, msgText, logDate) {
        var divMsg = $("#divUserMessage");
        divMsg.append("Posted by: " + fName + " " + lName + "<br/>");
        divMsg.append("Posted on: " + logDate + "<br/>");
        divMsg.append(msgText);
        divMsg.append("<hr/>");
    }

    function FormatDateString(logDate) {
        var d = new Date(parseInt(logDate.substr(6)));
        var year = d.getFullYear();
        var month = d.getMonth() + 1;
        var day = d.getDate();
        var hour = d.getHours();
        var minutes = d.getMinutes();
        var sec = d.getSeconds();

        return month + "/" + day + "/" + year + " " + hour + ":" + minutes + ":" + sec;
    }

</script></code>

上面的 HTML 标记非常简单,没什么特别之处。它只包含一些 div 元素、 textarea 和 button。我还为 div 和 textbox 元素应用了一些 CSS 样式。请记住,对于本教程来说,外观和感觉并不重要,因为我们主要关注的是功能本身。

转到 JavaScript 函数

上面的标记中有四个(4)个主要的 JavaScript 函数。第一个是 GetMessages() 函数。此函数使用 jQuery AJAX 向服务器发出异步 POST 请求,以获取数据库中的所有可用消息。如果 AJAX 调用成功,我们将遍历 JSON 响应中的每个项目,并调用 GenerateHTML() 函数来构建具有结果集的 UI。GenerateHTML() 函数使用 jQuery 函数来构建 HTML 并将值追加到现有的 div 元素。FormatDateString() 函数是一个方法,它将 JSON 日期格式转换为 JavaScript 日期格式,并将我们自己的日期格式返回给 UI 以供用户查看。Fetch() 函数调用 GetMessages() 函数并处理 div 的滚动位置。这意味着一旦有新消息到达,我们将自动滚动到 div 元素的底部。

$(function (){}) 是 jQuery's document ready 函数的简写语法,它会在所有 DOM 元素加载到浏览器中后触发。在这里,我们使用 jQuery 注册 div 的 onscroll 事件和按钮的 onclick 事件。在 onscroll 事件中,我们只是将一些值设置给一些全局变量以供将来使用。在 onclick 事件中,我们只是发出一个 AJAX 请求到服务器以将新数据添加到数据库。当 DOM 就绪时,我们还会调用 GetMessages() 函数以在浏览器首次加载时显示所有消息。您可能还注意到,我使用了 setInterval() 函数每五(5)秒自动从服务器拉取数据。因此,如果您的网站上的其他用户发送消息,那么其他用户将在 5 秒后自动收到。这是使用 AJAX 在给定时间内从服务器拉取数据的传统方式。

步骤 7

在 Index.cshtml 文件中添加以下标记:

<code><input type="hidden" id="hidUserID" value="@ViewBag.UserID" />  
@Html.Action("ShoutBoxPartial", "Home")</code>

输出

运行代码应该看起来像这样:

 

摘要

在本文中,我们学习了如何在 ASP.NET MVC 5 应用程序中使用 jQuery 和 AJAX 实现一个简单的“shoutbox”功能。

© . All rights reserved.