Nearing the end of my initial migration now in Part 6, I dove into Comment Listing, Adding New Comments and then emailing users a new comment was entered. (Other Posts: Part 1, Part 2, Part 3, Part 4 and Part 5). In Part 5, I imported the Comments, but wasn't doing anything but showing the Comment Count in the Post Title. In this post I will begin with what I did to display the comments. First off I added a new column to my PostComments to handle those Comments that were not approved or are pending approval (thinking about spam bots in particular). After adding that new column, I created a Stored Procedure to return the Comments for a given Post, some (maybe most) might find creating a Stored Procedure to simply return one Table is unnecessary, but I find it helps keep my C# much cleaner by adding that layer between my SQL Database and my C# code. [sql] CREATE PROCEDURE [dbo].[getPostCommentsSP] (@PostID INT) AS SELECT dbo.PostComments.Modified, dbo.PostComments.Body, dbo.PostComments.Name FROM dbo.PostComments WHERE dbo.PostComments.PostID = @PostID AND dbo.PostComments.IsApproved = 1 AND dbo.PostComments.Active = 1 [/sql] I proceeded to add a new function in my PostFactory to return the converted List collection:
public List<Objects.Comment> GetCommentsFromPost(int PostID) {
     using (var eFactory = new bbxp_jarredcapellmanEntities()) {
     return eFactory.getPostCommentsSP(PostID).Select(a => new Objects.Comment(a.Name, a.Body, a.Modified)).ToList(); }
}
]]>
Because I had already created a SinglePost ActionResult, I simply added the one line to also include my new created Comments List Collection:
model.Post.Comments = pFactory.GetCommentsFromPost(model.Posts[0].ID); ]]>
Since the main listings do not display the Comments, just the count, it was necessary to have a unique ActionResult. That being said, I did reuse my PartialView I created the other night, only adding to it:
if (@Model.Comments != null) {
     <div id="PostListing"> <div class="Title"> <h2>Comments</h2> </div> @foreach (var comment in @Model.Comments) {
     <div class="Comment"> <div class="Title"> <h3>@comment.Name - @comment.PostTime</h3> </div> <div class="Body"> @comment.Body </div> </div> }
</div> }
]]>
Because the Comments are otherwise null I can reuse the PartialView. After adding in all of the CSS Styles: [caption id="attachment_2039" align="aligncenter" width="300"]Comments Listing <span classin MVC4 Site" width="300" height="165" class="size-medium wp-image-2039" /> Comments Listing in MVC4 Site[/caption] Next on the list of things I wanted to accomplish is adding a form below the Comments Listing. Adding a pretty basic form for web developers is pretty trivial, however here is the code I am using:
if (@ViewBag.SinglePost != null) {
     <div class="CommentForm"> <input type="hidden" name="PostID" value="@Model.ID" /> <div class="Title"> <h2>Add a Comment</h2> </div> <div class="Fields"> <input type="text" id="PersonName" name="PersonName" class="k-textbox" required placeholder="Name" /><span class="requiredField">*</span><br/><br/> <input type="text" id="EmailAddress" name="EmailAddress" class="k-textbox" required placeholder="Email Address" /><span class="requiredField">*</span><br/><br/> </div> <div class="Body"> <textarea class="k-textbox" id="Body" name="Body" cols="500" maxlength="9999" wrap="soft" rows="5" placeholder="Enter comment here"></textarea><span class="requiredField">*</span><br/> </div> <div class="Submit"> <button class="k-button" type="submit">Submit Comment >></button> </div> </div> }
}
]]>
And the following line right above the CommentListing posted above:
@using (Ajax.BeginForm("AddComment", "Home", new AjaxOptions {
    UpdateTargetId = "PostListing"}
)) {
     ]]>
In my PostFactory I added the following code, note the line about auto-approving if the name/email combination had previously been approved just like WordPress does:
public void addComment(int PostID, string name, string email, string body) {
     using (var eFactory = new bbxp_jarredcapellmanEntities()) {
     var comment = eFactory.PostComments.Create(); comment.Active = true; comment.Body = body; comment.Created = DateTime.Now; comment.Email = email; comment.Modified = DateTime.Now; comment.Name = name; comment.PostID = PostID; comment.IsApproved = eFactory.PostComments.Any(a => a.Name == name && a.Email == email && a.Active && a.IsApproved); eFactory.PostComments.Add(comment); eFactory.SaveChanges(); }
}
]]>
A feature of WordPress I realized I enjoyed was the fact it emailed me when a new comment was entered in the system. So I figured I would add the same functionality to my MVC app. One thing I should note, this is far from ideal code. Think of a larger site, with hundreds or thousands of comments from users. The user would have to wait until all of the emails were sent and then return the user to the post they added their comment to. A better approach would be to offload this potentially long running task to a Windows Service - a feature I will be adding shortly.
// If the comment wasn't approved don't bother continuing to process if (!comment.IsApproved) {
     return; }
// Grab the existing approved comments and exclude the nearly added comment var existingComments = eFactory.getPostCommentsSP(PostID).Where(a => a.ID != comment.ID).ToList(); // Make sure there is at least 1 other comment in the system if (existingComments.Count == 1) {
     return; }
// Grab the Post to get the Post Title var post = eFactory.Posts.FirstOrDefault(a => a.ID == PostID); // Populate the Title and Body sections var Title = "Comment: \"" + post.Title + "\""; var Body = String.Format("The following comment by {
    0}
was added:" + System.Environment.NewLine + "{
    1}
", comment.Name, comment.Body); // Iterate through all of comments individually so as to not reveal other's email addresses to each other using (var smtpClient = new SmtpClient()) {
     foreach (var existingComment in existingComments) {
     smtpClient.Send(ConfigurationManager.AppSettings["EMAILADDRESS_CommentNotification"], existingComment.Email, Title, Body); }
}
]]>
So what is next? Implementing the WCF Service previously mentioned and the Windows Service mentioned above. This will allow me to easily create Windows Phone 8, Windows 8 Store apps or heck even a command line version if there was demand. More to come...