Views: 1165
Number of votes: 6
Average rating:

Extending Episerver’s IContent to manage Episerver Social Comments

Overview

The goal of this tutorial is to introduce the basics of the Episerver Social’s framework and its Comments feature. This tutorial also describes how to extend Episerver’s IContent type (available in the EPiServer.CMS.Core package) to support adding and retrieving comments in Episerver Social.

Prerequisites

Apply the Episerver.Social.Comments.Site package available at the Episerver Nuget feed to your Episerver site. This tutorial uses an Episerver Alloy for illustration.

Defining IContent’s extension methods

You may want to allow site visitors to post comments on various entities in your application. For example, in an Alloy site, you may want to allow site visitors (authenticated as well as anonymous) to comment on product pages in the site. The CommentExtensions class below defines an extension method that adds a comment to an instance of IContent using the Episerver Social Comment service.

    /// <summary>
    /// This class implements extension methods on an instance of Episerver IContent to
    /// support adding and retrieving Episerver Social comments posted on that instance.
    /// </summary>
    public static class CommentExtensions
    {
        private static ICommentService service;
    
        /// <summary>
        /// Constructor
        /// </summary>
        static CommentExtensions()
        {
            service = ServiceLocator.Current.GetInstance<ICommentService>();
        }

        // Format specifiers for building target content and author strings used to form
        // references in Episerver Social.
        private const string userReferenceFormat = "user://{0}";
        private const string resourceReferenceFormat = "resource://{0}";

        /// <summary>
        /// An extension method on the EPiServer.Core.IContent type to post a comment.
        /// </summary>
        /// <param name="content">An IContent instance stored in the content repository. Example: a product.</param>
        /// <param name="authorId">The unique identifier of the author who posted a comment.</param>
        /// <param name="comment">The body of the comment.</param>
        /// <param name="isVisible">Indicates whether or not this comment is visible.</param>
        /// <returns>the newly saved Comment instance.</returns>
        public static Comment AddComment(this IContent content, string authorId, string body, bool isVisible)
        {
            var authorReference = String.IsNullOrWhiteSpace(authorId) ?
                  Reference.Empty : 
                  Reference.Create(String.Format(userReferenceFormat, authorId));

            var targetReference = Reference.Create(
                  String.Format(resourceReferenceFormat, content.ContentGuid.ToString()));

            var newComment = new Comment(targetReference, authorReference, body, isVisible);
           
return service.Add(newComment);         }      }

 Now let’s add another extension method to the CommentExtensions class in the example above. This method retrieves a page of existing comments posted for an instance of IContent. The result page of comments is ordered by most recent comments (that is, descending order of comment created date).

        /// <summary>
        /// An extension method of the EPiServer.Core.IContent type to retrieve a page
        /// of Comments posted for an IContent instance. 
        /// </summary>
        /// <param name="content">A component stored in the content repository. Example: a product.</param>
        /// <param name="visible">The visibility filter by which to retrieve comments.</param>        
        /// <param name="offset">The zero-based start index of the comment to retrieve.</param>
        /// <param name="size">The maximum number of comments to retrieve.</param>
        /// <returns>
        /// Returns a page of comments sorted in descending order of the comment created date.
        /// </returns>
        public static ResultPage<Comment> GetComments(this IContent content,
                                                      Visibility visibile,
                                                      int offset,
                                                      int size)
        {
            var targetReference = Reference.Create(
                String.Format(resourceReferenceFormat, content.ContentGuid.ToString()));

            var criteria = new Criteria<CommentFilter>
            {
                Filter = new CommentFilter
                {
                    Parent = targetReference,
                    Visibility = visibile
                },
                PageInfo = new PageInfo
                {
                     PageOffset = offset,
                     PageSize = size,
                     CalculateTotalCount = false
                },
                OrderBy = new List<SortInfo>
                {
                    new SortInfo(CommentSortFields.Created, false)
                }
            };
            return service.Get(criteria);         }

For a complete listing of the CommentExtensions class, refer to the Episerver Social Alloy repository.

Adding comments to Episerver Social

Assume that the view of the ProductPage provides a textbox and a submit button to allow site visitors to comment on that product page. Also, assume that the submit button posts to the PostComment action of the ProductPage controller. The snippet below describes a possible implementation for the PostComment action that uses the AddComment extension method from the earlier section to save the comment to Episerver Social.

    [HttpPost]
    public ActionResult PostComment(ProductPage currentPage, string comment)
    {
        var authorId = String.Empty;

        if (this.User.Identity.IsAuthenticated)
        {
            authorId = this.User.Identity.GetUserId();
            if (authorId == null)
            {
                //For the sake of simplicity we set the authorid to empty if user identifier cannot be found or comment author is anonymous.
                authorId = String.Empty;
            }
        }

        var contentrepo = ServiceLocator.Current.GetInstance<IContentRepository>();         var productPageContent = contentrepo.Get<ProductPage>(currentPage.ContentLink);
        productPageContent.AddComment(authorId, comment, true);
        return RedirectToAction("Index");     }

Retrieving comments on IContent from Episerver Social

The product page may want to display any comments that have been posted on that product in the past. The code snippet below retrieves a comment page so that it can be displayed in the view of the product page.

        public ActionResult Index(ProductPage currentPage)
        {
            var contentrepo = ServiceLocator.Current.GetInstance<IContentRepository>();
            
var productPageContent =                 contentrepo.Get<ProductPage>(currentPage.ContentLink);             var commentPage = productPageContent.GetComments(Visibility.Visible, 0, 15);                      //Create the product view model and populate with commentPage             var productViewModel = …;                     return View(string.Format("~/Views/{0}/Index.cshtml", currentPage.GetOriginalType().Name), productViewModel);         }

The above sample retrieves the first page of 15 comments starting at offset zero. If the product page needs to allow site visitors to scroll through pages of comments, use a combination of the offset and size parameters of the GetComments extension method to implement paging support on comments.

Refer to the PageInfo and Best practices for paginating results sections in the Episerver Social Developer Guide for more information on the paging feature of the Episerver Social APIs.

Building references for comment authors and target content

The AddComment extension method above builds an instance of the Reference class when creating a new comment instance to store the comment author and target content identifiers. The ContentGuid of the IContent instance is used to establish the relationship between a comment and the content the comment applies to.

The Reference class in the Episerver Social platform refers to users or resources outside the platform. For more information on References, refer to the Reference and IDs section in the Episerver Social Developer Guide.

The AddComment action method in the Saving an Episerver Social Comment section above uses ASP.Net Identity Extensions ASP Net Identity extensions to retrieve the unique identifier of the author who is posting the comment by using this method:

        if (this.User.Identity.IsAuthenticated)
        {
            authorId = this.User.Identity.GetUserId();
            if (authorId == null)
            {
                //For the sake of simplicity we set the author to anonymous if identifier cannot be found. Depending on needs of your application you can handle this differently.
                authorId = String.Empty;
            }

        …

The Episerver Alloy site used in this tutorial uses Episerver ASPNetIdentity as the authentication mechanism to manage users and roles. Since ASP Net Identity is integrated into the Episerver Alloy site in this tutorial, the above technique to extract the identifier of the author using Identity extensions works successfully. If your application is using another means of authentication, use the appropriate technique for determining the author identifier from your user provider.

Interpreting references from Episerver Social

The GetComment extension method above returns a page of comments from the comment repository based on the criteria supplied. As a site developer, you may want to store author identifiers in Episerver Social to associate an Episerver Social comment with an author. However, displaying the identifiers of authors while rendering comments may not be preferred for readability or security reasons. The product page view may need to display the name of author in the product view instead of the user identifier to indicate the comment author.

For display purposes, to determine the user name of an author from the author identifier (which is stored in Episerver Social), you may need to query the user provider in your application. If using Episerver ASPNetIdentity (as is the case in this tutorial), you can determine the user name of the author from the author identifier as shown below:

        public string GetUserName(string authorId)       
{   var authorName = "Anonymous";             if (!String.IsNullOrWhiteSpace(authorId))             {                 var userManager = new UserManager<IdentityUser>(                    new UserStore<IdentityUser>(new ApplicationDbContext<IdentityUser>())   );                 var user = userManager.FindById(authorId);                 if (user != null)                 {                     authorName = user.UserName;                 }             }             return authorName;         }

Conclusion

The AddComment extension method adds comments that are by default created as visible in Episerver Social. Depending on the requirements of your application or whether comments in your application undergo a moderation process, you may want to create comments with the appropriate visibility setting when created initially.

The extension methods described in this tutorial can be handy when programmatically adding comments to Episerver Social for different types of content in Episerver. Additional extension methods can be created for posting replies to comments in Episerver Social.

  Please login to post a comment