Click here to Skip to main content
15,881,757 members
Articles / Web Development / HTML

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

Rate me:
Please Sign up or sign in to vote.
4.91/5 (5 votes)
2 Dec 2016CPOL5 min read 20.5K   632   7   2
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:

ASP.NET
<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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
A code monkey who loves to drink beer, play guitar and listen to music.

My Tech Blog: https://vmsdurano.com/
My Youtube Channel: https://www.youtube.com/channel/UCuabaYm8QH4b1MAclaRp-3Q

I currently work as a Solutions Architect and we build "cool things" to help people improve their health.

With over 14 years of professional experience working as a Sr. Software Engineer specializing mainly on Web and Mobile apps using Microsoft technologies. My exploration into programming began at the age of 15;Turbo PASCAL, C, C++, JAVA, VB6, Action Scripts and a variety of other equally obscure acronyms, mainly as a hobby. After several detours, I am here today on the VB.NET to C# channel. I have worked on Web Apps + Client-side technologies + Mobile Apps + Micro-services + REST APIs + Event Communication + Databases + Cloud + Containers , which go together like coffee crumble ice cream.

I have been awarded Microsoft MVP each year since 2009, awarded C# Corner MVP for 2015, 2016,2017 and 2018, CodeProject MVP, MVA, MVE, Microsoft Influencer, Dzone MVB, Microsoft ASP.NET Site Hall of Famer with All-Star level and a regular contributor at various technical community websites such as CSharpCorner, CodeProject, ASP.NET and TechNet.

Books written:
" Book: Understanding Game Application Development with Xamarin.Forms and ASP.NET
" Book (Technical Reviewer): ASP.NET Core and Angular 2
" EBook: Dockerizing ASP.NET Core and Blazor Applications on Mac
" EBook: ASP.NET MVC 5- A Beginner's Guide
" EBook: ASP.NET GridView Control Pocket Guide

Comments and Discussions

 
PraiseNice One Pin
DalalV7-Dec-16 1:07
DalalV7-Dec-16 1:07 
GeneralRe: Nice One Pin
Vincent Maverick Durano7-Dec-16 2:06
professionalVincent Maverick Durano7-Dec-16 2:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.