Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET MVC 5: Implementing a ShoutBox Feature Using jQuery and AJAX

0.00/5 (No votes)
2 Dec 2016 1  
This article will walk you through on implementing a simple shoutbox feature in your ASP.NET MVC 5 application.

Introduction

This article will walk you through on implementing a simple "shoutbox" feature in your ASP.NET MVC 5 application. I call the feature as "shoutbox" because users within your web site can exchange conversation with each other. You can think of it as a comment board, or pretty much similar to a group chat window. Please keep in mind that a "shoutbox" is not a full blown implementation of a chat feature. If you are looking for a chat application then you can refer my other article about Building a Simple Real-Time Chat Application using ASP.NET SignalR

Background

There are many possible ways to implement this feature, but since this article is targeted for beginners to intermediate developers, I have decided to use a simple and typical way of performing asynchronous operations using jQuery and AJAX. If you want a simple and clean API that allows you to create real-time web applications where the server needs to continuously push data to clients/browsers then you may want to look at ASP.NET SignalR instead.

Before you go any further, make sure that have a basic knowledge on ASP.NET MVC and how things works in MVC arch because I will not be covering those in this article. I would recommend following my previous articles about "Building Web Application Using Entity Framework and MVC 5" as I have integrated this feature in that application. If you haven’t gone through my previous articles then you can refer the following links below:

Let's Get Started!

Quote:

The downloadable source code does not contain the code mentioned in this article. What you need to do is to follow the steps mentioned in this article and integrate it to the existing downloadable code. It was my intent to have it this way so you will know where and which file are affected to integrate this feature instead of just running the code directly.

STEP 1:

The very first thing we need to do is to create a new table in the database for storing the message of each users. Now, go ahead and launch SQL Server Management Studio and create a Message table by running the following SQL script below:

<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>

STEP 2:

After that, switch back to Visual Studio and then open your EF designer by going to the Models folder > DB > DemoModel.edmx.

Right-click on the designer surface and then select "Update Model from Database". Select the Message table to add it to our entity set and click finish as shown in the figure below:

Image 1

STEP 3:

Add the following class under Models folder > 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>

The code above is just a simple class that houses some properties to store data from the database.

STEP 4:

Add the following code block under Models folder > 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>

The GetAllMessages() method fetches all messages that was stored from the database and assigning each field values to the corresponding properties of the UserMessage model. AddMessage() method simply add new sets of data to the database. Finally, GetUserID() method gets the user id of the current logged user by passing the login name as the parameter.

STEP 5:

Add the following action methods below under Controllers folder > 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>

In Index action method we call the GetUserID() method by passing the login name as the parameter to get the user ID of the current logged user. We then store the value in ViewBag so we can reference it in our View later on. The SendMessage() action method simply calls the AddMessage() method to insert new records to the database. The GetMessages() method fetches all user messages from the database.

STEP 6:

Create a new partial view under Views folder > Home and name it as "ShoutBoxPartial.cshtml",  then add the following markup below:

<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>

The HTML markup above is fairly simple and nothing really fancy about it. It just contain some div elements, textarea and button. I also applied few CSS style for the div and textbox elements. Keep in mind that the look and feel doesn't really matter for this tutorial as we are focusing mainly on the functionality itself.

Down to the JavaScript functions

There are four (4) main JavaScript functions from the markup above. The first one is the GetMessages() function. This function uses jQuery AJAX to issue an asynchronous post request to the server to get all available messages from the database. If the AJAX call is successful then we iterate to each items from the JSON response and call the GenerateHTML() function to build up the UI with the result set. The GenerateHTML() function uses jQuery function to build up the HTML and append the values to the existing div element. The FormatDateString() funtion is a method that converts JSON date format to JavaScript date format, and return our own date format to the UI for the users to see. The Fetch() function calls the GetMessages() function and handles the scroll position of the div. This means that we auto scroll to the bottom part of the div element once a new message will arrived.

The $(function (){}) is the short-hand syntax for jQuery's document ready function which fires once all DOM elements are loaded in the browser. This is where we register the onscroll event of div and the onclick event of button using jQuery. At onscroll event, we just set some values to some global variables for future use. At onclick event, we just issued an AJAX request to server to add new data to the database. When the DOM is ready we also call the GetMessages() function to display all messages on initial load of the browser. You may also noticed there that I have used the setInterval() function to automatically pull data from the server after every five (5) seconds. So if another users from your web site sends a message then it will automatically be available for other users after 5 seconds. This is the traditional way of using AJAX to pull data from the server for a given period of time.

STEP 7:

Add the following markup below in Index.cshtml file:

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

Output

Running the code should look something like this:

Image 2

 

Summary

In this article, we've learn how to implement a simple "shoutbox" feature using jQuery and AJAX within our ASP.NET MVC 5 application.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here