Building an Hierarchical Comment System in ASP.Net MVC, MS SQL Server, CSS and Jquery


The goal of this article is to teach how to structure and display hierarchical data. We will set up a database table structure that can hold data with unlimited parents and children.


Below is the completed sample app.


The Database Table Structure

Let's start by planning the table structure. We will be using a single self referenced table for our comment. The structure is shown in the image below.


As you can see we have five columns - CommentId which is the primary key, CommentText which holds the comment itself, Username which store the author of the comment, CommentDate and ParentId.

The most important column here is the ParentId which is a foreign key to CommentId - This is called self referenced.  How this works will be clear as we move on.

Creating the Visual Studio Project

Create a new ASP.Net MVC web application.  Open the index.cshtml file and add the following html codes

User Comment


The next thing is to open the site.css file and replace the code with the following styles
body {
    padding-top: 50px;
    padding-bottom: 20px;
}


.body-content {
    padding-left: 15px;
    padding-right: 15px;
}


.dl-horizontal dt {
    white-space: normal;
}

.page-title{
    margin-bottom:20px;
}

textarea {
    border-radius: 0 !important;
}

.panel-body {
    padding: 0 !important;
}

.comment-action {
    padding:0 !important;
    background: #f6f8f9 !important;
    clear:both;
    min-height:35px;
}

.submit-comment {
    background: #606d75;
    
    width: 130px;
    float: right;
    min-height: 35px;
    text-align:center;
}

    .submit-comment a {
        color: #fff !important;
        display:block;
        line-height:35px;
        text-decoration:none;
    }

ul.comments {
    margin: 0;
    list-style-type: none;
    padding:0;
    display:block;
}

.comments .comment .avatar {
    position: absolute;
    top: 8px;
    left: 10px;
}

.comments .comment {
    display: block;
    position: relative;
    padding-left: 92px;
    
}

.comments .comment .comment-body header {
    
    display: block;
    margin-bottom: 8px;
}

    .comments .comment .comment-body header .pubdate {
        color: #777;
        font-size: .9em;
    }

    .comments .comment .comment-body header .userlink {
        font-weight: bold;
        font-size: 1.1em;
    } 


.comments .comment .comment-body {
    padding: 0px 3px;
    padding-bottom: 12px;
    padding-top: 8px;
}


footer .reply-link {
    float: right;
    color: #777;
    font-size: 1em;
    text-decoration: none;
    
}

.comments .comment .replies {
    margin-top:2px;
    margin-bottom: 3px;
}



If you run the app now the result should look like this

asp-net-comment-system-application

The Application Repository

Right click on the models folder add a new ADO.NET Data Entity Model and the comment table. We need to create methods to fetch and add comments into the comment table.

Right click on the models folder and add a class named CommentRepository and replace the code with the following:
public class CommentRepository
    {
        CommentEntities context = new CommentEntities();

        public IQueryable GetAll()
        {
            return context.Comments.OrderBy(x => x.CommentDate);
        }

        public commentViewModel AddComment(commentDTO comment)
        {
            var _comment = new Comment()
            {
                ParentId = comment.parentId,
                CommentText =comment.commentText,
                Username = comment.username,
                CommentDate =DateTime.Now
            };

            context.Comments.Add(_comment);
            context.SaveChanges();
            return context.Comments.Where(x => x.CommentID == _comment.CommentID)
                    .Select(x => new commentViewModel
                    {
                        commentId = x.CommentID,
                        commentText =x.CommentText,
                        parentId =x.ParentId,
                        commentDate =x.CommentDate,
                        username =x.Username

                    }).FirstOrDefault();
        }
    }

After our repository, we also need two methods in the home controller. Modify the HomeController code to reflect this two methods.
public PartialViewResult CommentPartial()
        {
            var comments = repo.GetAll();
            return PartialView("_CommentPartial", comments);
        }

        public JsonResult addNewComment(commentDTO comment)
        {
            try
            {
                var model = repo.AddComment(comment);

                return Json(new { error = false,result=model }, JsonRequestBehavior.AllowGet);

            }
            catch (Exception)
            {
                //Handle Error here..
            }

            return Json(new { error = true }, JsonRequestBehavior.AllowGet);
        }


As you can see, the first method is a PartialViewResult which means that we are returning a partialview. So let's create the partial view. Add a partial view named _CommentPartial in the shared folder in the root of the solution. Now update the html code in the index.cshtml file by adding the partial view like so:
........

@Html.Action("CommentPartial")

Using the Razor @Helper syntax to Render Comments 

The @helper syntax within Razor enables you to easily create re-usable helper methods that can encapsulate output functionality within your view templates. They enable better code reuse, and can also facilitate more readable code. Let’s look at how we will create a recursive comment rendering using this helper. Open up the partial view and add the following code:
@model IEnumerable

@helper RenderComment(IEnumerable comments)
{
    foreach (var comment in comments)
    {

  • @comment.Username - posted @comment.CommentDate.ToString("dd-MM-yyyy")

    @comment.CommentText

    @{ var children = Model.Where(x => x.ParentId == comment.CommentID).ToList(); if (children.Count() > 0) {
      @RenderComment(children);
    } }
  • } }
      @RenderComment(Model.Where(x => x.ParentId == 0))

    Adding Comment Javascript and Template

    If we currently click on the Submit button in the browser we wont get any effect. In order to manipulate comment templates we will require a javascript library called HandleBars. Download and include it in the scripts folder and then add the reference to the index.cshtml file like so:

    @section scripts{
        
    }
    
    We will define two templates, the first one is for the parent comments and the second will be for the replies. The comment template look like this:
    
    
    
    And the reply template:
    
    
    
    We will be using ajax to submit and retrieve comments so lets write the ajax method. In the script section of the index.cshtl file create a javascript function called addNewComment like so:
         function addNewComment(data) {
                return $.ajax({
                    type: "POST",
                    url: '@Url.Action("addNewComment", "Home")',
                    data: data,
                    dataType: 'json',
                    contentType: 'application/json;charset=utf-8'
                });
            }
    
    The complete javascript code that is responsible for adding comments and replies look like so:
    
    
    @section scripts{
        
        
    
    
    }
    
    That is it! I have included the link for the complete source code in my github page. Your comments and suggestions are welcome.

    No comments

    Powered by Blogger.