Blog posts by Shilpa Joshi2017-06-08T21:15:04.0000000Z/blogs/shilpa-joshi/Optimizely WorldUsing Episerver Social for finding popular content/blogs/shilpa-joshi/dates/2017/6/using-episerver-social-for-finding-popular-content/2017-06-08T21:15:04.0000000Z<h2>Overview</h2>
<p>Enabling the content rating feature in your website can help collect valuable feedback from site visitors. The <a href="/link/9c1c5585ade74ebba82aa88fae6c1c4c.aspx">Episerver Social</a> platform provides a powerful ratings and statistics system that enables site developers to allow users to submit their content ratings, which the Episerver Social platform then uses to tabulate rating statistics. The generated statistical data can be a useful tool in determining how useful the content on your site appears to site visitors. Also, less popular content may be a potential candidate for further improvement.</p>
<p>This blog illustrates how to collect content ratings from your site visitors then gather the tabulated rating statistical data using the <a href="/link/91528739cfd240a2852b2d9f3bb9887f.aspx">Episerver Social RatingStatistics service</a> to identify <em>popular </em>or <em>less-popular </em>content.</p>
<h2>Prerequisites</h2>
<p>Apply the Episerver.Social.Ratings.Site package available at the <a href="http://nuget.episerver.com/en/" target="_blank">Episerver Nuget feed</a> to your Episerver site. An Episerver Alloy site was used for developing the sample snippets in this article.</p>
<h2>Collecting ratings from site visitors</h2>
<p>Using the Episerver Alloy site for an example, let us say we want to allow site visitors (authenticated as well as anonymous) to rate the product pages (of page type ProductPage) that are present in the site.</p>
<p>The first step in collecting ratings is defining a rating scheme. You may want visitors to rate a product page using a combination of <em>Like</em> and <em>Dislike</em> buttons, or collect ratings on a scale of 1 through 5, or a scale of 1 through 100 to represent percentages.</p>
<p>The next step is to compose a rating object and submit it to the Episerver Social Rating system. The Rating class is used to represent a rating. A rating instance is comprised of three parts.</p>
<p><strong>1. The reference to the user rating the resource.</strong></p>
<p>The Reference class in the Episerver Social platform refers to users or resources outside the platform. Some examples of a user reference are user names or unique user identifiers assigned by the user provider configured for your application. If your application has multiple user providers, the user reference scheme could be combination of the provider and user identifiers: Reference.Create($"user://{providerid}/{userid}").</p>
<p>You are free to come up with a reference scheme that best suits your needs for uniquely identifying resources external to Episerver Social.<span> For more information on References, refer to the <em>Reference and IDs</em> section in the </span><a href="/link/a09c5c7c7ca54b9b8bcb06d846cf9031.aspx#referenceandIDs">Episerver Social Developer Guide</a><span>.</span></p>
<p><strong> 2. The reference of the resource being rated.</strong></p>
<p>Some examples of resource references are page or product identifiers assigned by your content repository, such as Reference.Create(currentPage.ContentGuid.ToString()).</p>
<p><strong> 3. An integer value representing the rating.</strong></p>
<p>For example, in the Like-Dislike case above, a rating value of 1 could be mapped to the Like button and a value of -1 or 0 could be mapped to the Dislike button.</p>
<p>Once you identify the various components of a rating, the next step is to submit the rating. A sample UI to collect a user feedback is shown below. If a page has never been rated, you may want to prompt an incoming visitor to be the first rater for that page.</p>
<p><img style="border: 1px solid black;" title="rate content" alt="rate content" src="/link/5686b0dfcbd7415facb620ded226fbca.aspx" height="143" width="312" /></p>
<p>A complete implementation of the UI is outside the scope of this blog, but you may refer to the <a href="https://github.com/episerver/SocialAlloy/tree/master/src/EPiServer.SocialAlloy.Web/Social/Extensions">Episerver Social Alloy repository</a> that uses Episerver block types to render rating forms that can be used across different product pages. A snippet to submit ratings is shown below.</p>
<pre class="language-csharp"><code>private Rating AddRatingForProduct(ProductPage currentPage, int ratingValue)
{
var productReference = Reference.Create(currentPage.ContentGuid.ToString());
Reference userReference = null;
if (this.User.Identity.IsAuthenticated)
{
userReference = Reference.Create(this.User.Identity.Name);
}
else
{
userReference = Reference.Create(System.Guid.NewGuid().ToString());
}
var rating = new Rating(userReference, productReference, new RatingValue(ratingValue));
return ratingService.Add(rating);
}</code></pre>
<p>The code above allows anonymous visitors to rate the product page. Based on the requirements of your application, you may want to allow or disallow the submission of anonymous ratings.</p>
<p>The Episerver Social system restricts a user to rate a particular resource only once (although an existing user rating value for a resource can be updated). To allow multiple anonymous visitors to rate the same resource, the code above represents each anonymous rater with an internally generated unique identifier. Depending on your application, you could instead use a unique visitor ID (from a cookie, for example) to track anonymous raters.</p>
<h2>Retrieve rating and statistics for a page</h2>
<p>If a product page has been rated in the past, you may want to retrieve and display rating statistics that indicate the average rating of that page and the total number of existing ratings. The snippet below uses the <a href="/link/91528739cfd240a2852b2d9f3bb9887f.aspx">Episerver Social RatingStatistics service</a> to retrieve rating statistics for that page.</p>
<p><span><img style="border: 1px solid black;" title="average rating" alt="average rating" src="/link/65dbf14bea9e4aa3990453e1c92c143b.aspx" height="71" width="213" /></span></p>
<pre class="language-csharp"><code>private RatingStatistics GetAverageRatingForProduct(ProductPage currentPage)
{
var productReference = Reference.Create(currentPage.ContentGuid.ToString());
var criteria = new Criteria<RatingStatisticsFilter>
{
Filter = new RatingStatisticsFilter
{
Targets = new List<Reference> { productReference }
},
PageInfo = new PageInfo { PageSize = 1 }
};
var ratingStatisticsPage = ratingStatisticsService.Get(criteria);
return ratingStatisticsPage.Results.FirstOrDefault();
}</code></pre>
<p>Note that the page size for the query above is set to a value of 1, since there can be at the most only one statistics generated for a given resource.</p>
<p>To display any previously submitted rating of the logged-in user for the product page they are currently visiting, use the <a href="/link/91528739cfd240a2852b2d9f3bb9887f.aspx">Episerver Social Rating service</a> as shown below to retrieve the existing rating.</p>
<pre class="language-csharp"><code>private Rating GetUserRatingForProduct(ProductPage currentPage)
{
Rating rating = null;
if (this.User.Identity.IsAuthenticated)
{
var productReference = Reference.Create(currentPage.ContentGuid.ToString());
var userReference = Reference.Create(this.User.Identity.Name);
var criteria = new Criteria<RatingFilter>
{
Filter = new RatingFilter
{
Targets = new List<Reference> { productReference },
Rater = userReference
},
PageInfo = new PageInfo { PageSize = 1 }
};
var ratingPage = ratingService.Get(criteria);
rating = ratingPage.Results.FirstOrDefault();
}
return rating;
}</code></pre>
<h2>Retrieve popular content in your site</h2>
<p>The RatingStatistics service can be used to retrieve a page of rating statistics sorted by the mean rating value in an order from highest to lowest. The product pages that appear higher up in the page can be perceived as items that were more appealing or popular amongst site visitors. Items lower down in the list could be perceived as less attractive to visitors and thereby could be potential candidates for further tweaking or enhancements.</p>
<p>For example, if ratings have been submitted for the various product pages in an Episerver Alloy site, you could present the tabulated rating statistics for these pages (possibly in a site administrator view of your site) as shown in the picture below.</p>
<p> <img title="popular content" alt="popular content" src="/link/b6b70683a91b4ad8b51d4fb402a0ebf7.aspx" height="341" width="296" /></p>
<p>You could infer from the view above that the <em>Alloy Meet</em> product seems to be more appealing to visitors than other products and the <em>Alloy Track</em> product may need to be revisited to catch the eye of visitors.</p>
<p>The RatingStatistics service exposes a Get method that can be used to easily collect the information required to display the view above. A sample snippet is below.</p>
<pre class="language-csharp"><code>private ResultPage<RatingStatistics> GetPopularProducts()
{
var criteria = new Criteria<RatingStatisticsFilter>
{
PageInfo = new PageInfo { PageSize = 10, PageOffset = 0 },
OrderBy = new List<SortInfo>
{
new SortInfo(RatingStatisticsSortFields.Mean, false)
}
};
var ratingStatisticsPage = ratingStatisticsService.Get(criteria);
return ratingStatisticsPage;
}</code></pre>
<p>The above sample retrieves the first page of 10 rating statistics from the repository sorted by the average rating value in the order of highest to lowest. To retrieve subsequent pages of statistics, use the PageInfo property of the criteria object.</p>
<p><span>Refer to the <em>PageInfo</em> and <em>Best practices for paginating results</em> sections in the </span><a href="/link/a09c5c7c7ca54b9b8bcb06d846cf9031.aspx#criteria">Episerver Social Developer Guide</a><span> for more information on the paging feature of the Episerver Social APIs.</span></p>
<p><span>A gist with the source of the sample product controller used in this article can be found here:<br /></span><span><a href="https://gist.github.com/epishilpa/94e49d0f927e149502fd738a1fd4bf2f">https://gist.github.com/epishilpa/94e49d0f927e149502fd738a1fd4bf2f</a>.</span></p>
<h2>Remarks</h2>
<p>The RatingStatistics service also exposes an Update API that allows adding additional data to ratings statistics that were internally calculated for a resource. If your business needs require the presence of supplemental statistical data, you can attach it as extension data to the statistics generated by Episever Social. If you choose to do so, the GetPopularProducts method can be updated to use another overload of the Get API that allows retrieving and filtering by extension data.</p>
<p>For more information on the extending rating statistics with extension data, refer to the <a href="/link/e1b4b4e5154c4e80985c0cc0c83975e5.aspx">Extending ratings with composites</a> section of the Episerver Social Developer Guide.</p>Extending Episerver’s IContent to manage Episerver Social Comments/blogs/shilpa-joshi/dates/2017/2/extending-episervers-icontent-to-manage-episerver-social-comments/2017-03-10T15:06:17.6100000Z<h2>Overview</h2>
<p>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 <a href="/link/9c1c5585ade74ebba82aa88fae6c1c4c.aspx">Episerver Social</a>.</p>
<h2>Prerequisites</h2>
<p>Apply the Episerver.Social.Comments.Site package available at the <a href="http://nuget.episerver.com/feed/">Episerver Nuget feed</a> to your Episerver site. This tutorial uses an Episerver Alloy for illustration.</p>
<h2>Defining IContent’s extension methods</h2>
<p>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 <a href="/link/03f8ccf5bec34e048013d2824c8166ea.aspx">Episerver Social Comment service</a>.</p>
<pre class="language-html"><code> /// <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);
<br /> return service.Add(newComment);
}
}</code></pre>
<p> 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).</p>
<pre class="language-html"><code> /// <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)
}
};<br />
return service.Get(criteria);
}</code></pre>
<p>For a complete listing of the CommentExtensions class, refer to the <a href="https://github.com/episerver/SocialAlloy/tree/master/src/EPiServer.SocialAlloy.Web/Social/Extensions">Episerver Social Alloy repository</a>.</p>
<h2>Adding comments to Episerver Social</h2>
<p>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.</p>
<pre class="language-html"><code> [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;
}
}
<br /> var contentrepo = ServiceLocator.Current.GetInstance<IContentRepository>();
var productPageContent = contentrepo.Get<ProductPage>(currentPage.ContentLink);
<br /> productPageContent.AddComment(authorId, comment, true);
<br /> return RedirectToAction("Index");
}</code></pre>
<h2>Retrieving comments on IContent from Episerver Social</h2>
<p>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.</p>
<pre class="language-html"><code> public ActionResult Index(ProductPage currentPage)
{
var contentrepo = ServiceLocator.Current.GetInstance<IContentRepository>();
<br /> 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);
}</code></pre>
<p>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.</p>
<p><span>Refer to the <em>PageInfo</em> and <em>Best practices for paginating results</em> sections in the <a href="/link/a09c5c7c7ca54b9b8bcb06d846cf9031.aspx#criteria">Episerver Social Developer Guide</a> for more information on the paging feature of the Episerver Social APIs.</span></p>
<h2>Building references for comment authors and target content</h2>
<p>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.</p>
<p>The Reference class in the Episerver Social platform refers to users or resources outside the platform.<span> For more information on References, refer to the <em>Reference and IDs</em> section in the <a href="/link/a09c5c7c7ca54b9b8bcb06d846cf9031.aspx#referenceandIDs">Episerver Social Developer Guide</a>.</span></p>
<p>The AddComment action method in the <em>Saving an Episerver Social Comment</em> section above uses <a href="https://www.asp.net/identity">ASP.Net Identity Extensions</a> ASP Net Identity extensions to retrieve the unique identifier of the author who is posting the comment by using this method:</p>
<pre class="language-html"><code> 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;
}
<br /> …</code></pre>
<p>The Episerver Alloy site used in this tutorial uses <a href="/link/5da1a6cc4d7f4f95a9daf3b5bb726748.aspx">Episerver ASPNetIdentity</a> 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.</p>
<h2>Interpreting references from Episerver Social</h2>
<p>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.</p>
<p>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:</p>
<pre class="language-html"><code> public string GetUserName(string authorId) <br /> {
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;
}</code></pre>
<h2>Conclusion</h2>
<p>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.</p>
<p>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.</p>