Niklas Melinder
Nov 1, 2010
  8177
(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?

Niklas Melinder
Niklas Melinder 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.

Niklas Melinder
Niklas Melinder 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.

Niklas Melinder
Niklas Melinder 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.

Niklas Melinder
Niklas Melinder 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
Introducing Optimizely Graph Source .NET SDK

Overview Of Optimizely Graph Optimizely Graph is a cutting-edge, headless content management solution designed to integrate seamlessly with any...

Jake Minard | Oct 10, 2024

Content Search with Optimizely Graph

Optimizely Graph lets you fetch content and sync data from other Optimizely products. For content search, this lets you create custom search tools...

Dileep D | Oct 9, 2024 | Syndicated blog

Omnichannel Analytics Simplified – Optimizely Acquires Netspring

Recently, the news broke that Optimizely acquired Netspring, a warehouse-native analytics platform. I’ll admit, I hadn’t heard of Netspring before,...

Alex Harris - Perficient | Oct 9, 2024 | Syndicated blog

Problem with language file localization after upgrading to Optimizely CMS 12

Avoid common problems with xml file localization when upgrading from Optimizely CMS 11 to CMS 12.

Tomas Hensrud Gulla | Oct 9, 2024 | Syndicated blog