Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more


Nov 1, 2010
  8286
(1 votes)

A social plugin for EPiServer

The background

Since the release of EPiServer 6 i haven´t been engaged in any pure EPiServer projects and therefor haven´t got to use the new and shiny features that comes with version 6. Because of that (and the fact that my EPiServer developer certificate soon will expire again) I started playing around with the Dynamic Data Store recently to get a better grip on it.

The goal

The goal of this, other than me getting to know DDS, was to create a plugin for EPiServer that provided some basic “social” features like comments and ratings. There has been numerous blogposts and demos on how to implement this kind of functionality using DDS, but I thought I would take it a step further and create a ready-to-use plugin.

Besides that, I wanted the use of it to be as simple as possible. No configuration, no setup, no extra files. Just drop an assembly in the bin-folder and get busy coding.

The result

The result of all this became a plugin that provides a simple API for creating comments and ratings for EPiServer pages. It also contains a simple editmode plugin for managing these for each page.

This is to be considered in an alpha stage. There still remains some work before it is ready and additional features will be added along the way. Feel free to try it out.

This post focuses on how to use the EPiSocial plugin rather than how DDS works.

Single assembly deployment

Well, almost. The plugin itself is just a single assembly, but it depends on both AutoMapper and StructureMap.

So the deployment consists of adding the following three assemblies to your bin-folder:

  • EPiSocial.dll
  • AutoMapper.dll
  • StructureMap.dll

Then add a reference to EPiSocial and you´re done.

POCO objects

The comments and ratings are simple POCO objects and looks like this:

PageComment class:

   1: public class PageComment
   2: {
   3:         public string Id { get; set; }
   4:         public string Text { get; set; }
   5:         public int PageId { get; set; }
   6:         public string PageLanguage { get; set; }
   7:         public Author Author { get; set; }
   8:         public DateTime Created { get; set; }
   9: }

PageRating class:

   1: public class PageRating
   2: {
   3:         public string Id { get; set; }
   4:         public int Rating { get; set; }
   5:         public int PageId { get; set; }
   6:         public string PageLanguage { get; set; }
   7:         public Author Author { get; set; }
   8:         public DateTime Created { get; set; }
   9: }

Author class:

   1: public class Author
   2: {
   3:         public string Email { get; set; }
   4:         public string Name { get; set; }
   5: }

Usage - The easy way

The EPiSocial plugin provides a EPiSocialService class that is the entrypoint for using the API. It has a singleton instance, EPiSocialService.Instance, to use.

The EPiSocialService itself has two properties, a CommentRepository and a RatingRepository, that provides methods for adding, retrieving and removing comments/ratings.

Add a comment:

   1: var pageComment = new PageComment
   2:                   {
   3:                         Text = "Some text",
   4:                         PageId = 3,
   5:                         PageLanguage = "sv",
   6:                         Created = DateTime.Now,
   7:                         Author = new Author { Name = "Some name" }
   8:                   };
   9:  
  10: EPiSocialService.Instance.CommentRepository.AddComment(pageComment);

Get comments for a page:

   1: var commentsForPage = EPiSocialService.Instance.CommentRepository.GetCommentsForPage(3);

Languagespecific overload:

   1: var commentsForPage = EPiSocialService.Instance.CommentRepository.GetCommentsForPage(3, "sv");

Usage - The recommended way

Even though the above example is really quick and easy to use, you really should not depend directly on the EPiSocialService class. As the good developer you are you should instead have dependencies on the interface IEPiSocialService or any of the repository interfaces ICommentRepository or IRatingRepository.

Editmode plugin

When adding the EPiSocial assembly you also get an editmode plugin added to EPiServer. It is a tab in the editpanel of each page named “EPiSocial”. The plugin contains some statistics for the current page and the ability to reset ratings and remove unwanted comments.

EPiSocial

This has been an introduction to EPiSocial. The project is just in it´s first stumbling steps and any feedback is appreciated.

The plugin can be downloaded here for now. Feel free to try it out.

Nov 01, 2010

Comments

smithsson68@gmail.com
smithsson68@gmail.com Nov 1, 2010 12:55 PM

Hi.

Two things:

1) If the PageComment and PageRating classes are stored in the DDS then your Id properties should be of type Guid or Identity. In fact the DDS should be throwing an exception saying this.

See the Identity Management section of http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-60/Dynamic-Data-Store/

2) Entities that are related to CMS pages are much better stored through the PageObjectManager (which uses DDS underneath) as this will give you free import/export and
Mirroring support for your ratings and comments.

See http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-60/Page-Objects/ for more information.

/Paul.

Magnus Rahl
Magnus Rahl Nov 1, 2010 01:27 PM

Paul, is there a way to use PageObjects and still be able to easily query the store for a class, say Ratings, to create aggregates over all pages. I mean like calculating the average rating for all pages and getting the top rated pages?

Nov 1, 2010 01:31 PM

Thanks for the quick feedback.

1. The PageComment/PageRating objects are mapped to DDS comment/rating objects in the background, and then the Identity is created. I didn´t want to have a hard coupling to EPiServer/DDS. With this approach the CommentRepository can be exchanged to any other storage; XML, document database etc. This makes the whole plugin a lot more flexible.

2. I´ll have to take a look at that.

// Niklas

smithsson68@gmail.com
smithsson68@gmail.com Nov 1, 2010 01:48 PM

@Magnus

When using the PageObjectManager the actual entity objects are stored in the DDS in the normal way. Johan Olofsson has give an example in the forum entry here of how to get average ratings:

http://world.episerver.com/Templates/Forum/Pages/thread.aspx?id=37962

although I don't really agree with him that you can't use page objects to do this. The trick is to make sure your Rating class has a property to capture the page id. This may seem to defeat the point of using page objects but don't forget the free import/export/mirroring support which you would have to do yourself otherwise.

/Paul.





Magnus Rahl
Magnus Rahl Nov 1, 2010 03:44 PM

Thanks for the response Paul. I was clear on how to do the actual aggregation, if I could only get a queryable object containing all the ratings. Does the PageObjectManager use a class-specific store for each object type passed in so I can get PageRatings stored as PageObjects by calling GetStore(typeof(PageRating))? Is it acheived by using a EPiServer.Data.Dynamic.EPiServerDataStoreAttribute to map the PageRating class to a specific store, or do PageObjects work that way OOTB?

smithsson68@gmail.com
smithsson68@gmail.com Nov 2, 2010 09:44 AM

@Magnus.

Objects stored via the PageObjectManager work exactly the same as if stored directly via the DDS API's. So if your class is called PageRating then you can get a store like this:

var store = DynamicDataStoreFactory.Instance.GetStore(typeof(PageRating));

This call takes account of any Type to Store mapping either via the EPiServerDataStoreAttribute or via the GlobalTypeToStoreMap API.

/Paul.

Nov 2, 2010 11:45 AM

Thank you for your input.

I´m not convinced though, seems to me that using PO might get messier and the only real benefit is support for mirroring and import/export. And to do aggregations for multiple pages I still have to use plain DDS, right? Please correct me if I´m wrong.

To add a comment for example, using DDS I can just insert a new object to the store. Using PO I have to do a lot of things:

- Load the PO
- If exists, add to PO
- If not exists, create a new PO
- Save PO

For now, I can actually live with not having mirroring and import/export.

// Niklas

smithsson68@gmail.com
smithsson68@gmail.com Nov 3, 2010 09:42 AM

@Niklas

Everything you say is correct but I must take you up on one point. You say that _you_ can live without Mirroring/Import/Export but these features aren't for developers, they're for editors and site owners.

It could be very frustrating for a site owner using your components for page comments, rating etc to see that those items do not follow the pages when exported / mirrored.

/Paul.

Nov 3, 2010 11:25 AM

You have a point in that, of course.

I´m actually working on a PageObject implementation of the repositories. I´ll try to add a post on that soon.

seth@blendinteractive.com
seth@blendinteractive.com Nov 8, 2010 02:34 AM

If you're interested in allowing access to the source and taking contributions I'd gladly help out on this. It would be great to have a commonly used commenting method on episerver projects.

Nov 9, 2010 10:30 PM

@Seth

I´m thinking of doing this further on, but first I will focus on getting the plugin in a good enough shape. At the moment it is still in a alpha/beta stage.

I will try to keep posting about the progress here, stay tuned.

Please login to comment.
Latest blogs
Another console app for calling the Optimizely CMS REST API

Introducing a Spectre.Console.Cli app for exploring an Optimizely SaaS CMS instance and to source code control definitions.

Johan Kronberg | Mar 11, 2025 |

Extending UrlResolver to Generate Lowercase Links in Optimizely CMS 12

When working with Optimizely CMS 12, URL consistency is crucial for SEO and usability. By default, Optimizely does not enforce lowercase URLs, whic...

Santiago Morla | Mar 7, 2025 |

Optimizing Experiences with Optimizely: Custom Audience Criteria for Mobile Visitors

In today’s mobile-first world, delivering personalized experiences to visitors using mobile devices is crucial for maximizing engagement and...

Nenad Nicevski | Mar 5, 2025 |

Unable to view Optimizely Forms submissions when some values are too long

I discovered a form where the form submissions could not be viewed in the Optimizely UI, only downloaded. Learn how to fix the issue.

Tomas Hensrud Gulla | Mar 4, 2025 |

CMS 12 DXP Migrations - Time Zones

When it comes to migrating a project from CMS 11 and .NET Framework on the DXP to CMS 12 and .NET Core one thing you need to be aware of is the...

Scott Reed | Mar 4, 2025

New Optimizely Certifications – Take Your Skills to the Next Level

Big news! We’ve just launched five new Optimizely certifications to help you validate your skills and stand out in the world of digital experience...

Satata Satez | Feb 28, 2025