Skip to content

EntityService Sitecore.Services.Client

Sitecore.Services.Client provides a powerful and flexible method of creating Web API based services within Sitecore. Using the provided interfaces and the repository pattern means that you will be building services in a consistent way, allowing you to build more flexible services and reduce the time to develop and maintain them. Sitecore.Services.Client was introduced first in Sitecore 7.5 and supported also in Sitecore 8.

Sitecore.Services.Client consists of two separate services. ItemService which allows you to work with standard Sitecore Item class. The other is EntityService which allows you to work with business entities that you create, and allows you implement the business logic as you require.

Both EntityService and ItemService offers a number of ways of consuming the service, allowing you to work via web requests to the rest API, use the JavaScript API or bind to SPEAK components. This post I will be using the JavaScript API with EntityService in context of an Sitecore SPEAK application.

Model

The first stage of creating a EntityService based service is to create a Model. This model will define your business entity you wish to work with. All Models have to implement the Sitecore.Services.Core.Model.EntityIdentity class.

namespace MikeRobbins.News.Models
{
 public class NewsArticle: Sitecore.Services.Core.Model.EntityIdentity
 {
public string Title{ get; set; }
public string Description{ get; set; }
 }
}

Repository

Create a repository based on the IRespository interface. E.g Sitecore.Services.Core.IRepository<NewsArticle>. Once you implement the interface you can start to code up the functionality that your EntityService will expose.

IRepository will give you methods for Add, Delete, Exists, FindById, GetAll and Update of your Model. You can however extend this if you require.


using MikeRobbins.News.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Sitecore.Data;

namespace MikeRobbins.News.Repository
{
 public class NewsArticleRepository : Sitecore.Services.Core.IRepository<NewsArticle>
 {

 public void Add(NewsArticle entity)
 {
 throw new NotImplementedException();
 }

 public void Delete(NewsArticle entity)
 {
 throw new NotImplementedException();
 }

 public bool Exists(NewsArticle entity)
 {
 var newsArticle = Sitecore.Data.Database.GetDatabase("master").GetItem(new ID(entity.Id));

 return newsArticle != null;
 }

 public NewsArticle FindById(string id)
 {
 var newsArticle = Sitecore.Data.Database.GetDatabase("master").GetItem(new ID(id));

 if (newsArticle != null)
 {
 return new NewsArticle() { Id = newsArticle.ID.ToString(), DisplayName = newsArticle.DisplayName };
 }
else
{
return null;
}
 }

 public IQueryable<NewsArticle> GetAll()
 {
 throw new NotImplementedException();
 }

 public void Update(NewsArticle entity)
 {
 }
 }
}

Controller

Next create a controller and add the ServicesController attribute. Implement the EntiryService<T> class where T is your Model. Create a second constructor that creates new instance of your repository class.

namespace MikeRobbins.News.Controllers
{
 [ValidateAntiForgeryToken]
 [Sitecore.Services.Core.ServicesController]
 public class NewsArticleController : EntityService<NewsArticle>
 {
 public NewsArticleController(IRepository<NewsArticle> repository)
 : base(repository)
 {
 }

 public NewsArticleController()
 : this(new NewsArticleRepository())
 {
 }

 }
}

SPEAK PageCode

Using RequireJS require a reference to the entity service JavaScript library, and update the define element to include the entityService.

require.config({
 paths: {
 entityService: "/sitecore/shell/client/Services/Assets/lib/entityservice"
 }
});

define(["sitecore", "jquery", "underscore", "entityService"], function (Sitecore, $, _, entityService) {
 var News = Sitecore.Definitions.App.extend({

 initialized: function () {

 },
 });
return News;
});

Working with EntityService via the JavaScript API

To work with EntityService via the JavaScript API you create an instance of EntityService passing in the url property. The url property is the url of your controller. EntityService is always prefixed with “/sitecore/api/ssc”. The next part of the url is the namespace containing your controller with the “.” replaced with “-” followed by your controller name.

E.g. If you your controller is in the namespace MikeRobbins.News.Controllers and called NewsArticleController. Your url would be “/sitecore/api/ssc/MikeRobbins/api/ssc/MikeRobbins-News-Controllers/newsarticlearticle”

Get Entities Example

Create an instance of EntityService with the service url, you can then call fetchEntities. This will then call the GetAll method within your repository defined within the controller. An array of the entities are then returned.

GetNewsArticles: function () {

 var newsService = new entityService({
 url: "/sitecore/api/ssc/MikeRobbins-News-Controllers/newsarticle"
 });

 var result = newsService.fetchEntities().execute().then(function (newsArticles) {
  for (var i = 0; i < newsArticles.length; i++) {
 var title = newsArticles[i].Title;
}
 });

 },

Get Entity Example

Create an instance of EntityService with the service url, you can then call the fetchEntity function passing in an id of an entity. This will then call the FindById method within your repository defined within the controller. An entity class in returned.

GetNewsArticle: function () {

 var newsService = new entityService({
 url: "/sitecore/api/ssc/MikeRobbins-News-Controllers/newsarticle"
 });

 var result = newsService.fetchEntity("73e3a4fe-7d42-4ed9-b66e-ad948f340f27").execute().then(function (newsArticle) {
 var title = newsArticle.Title;
 });

 },

Update Entity Example

Create a an instance of EntityService with the service url, you can then call the fetchEntity function passing in an id of an entity. Once you have an entity returned, make the required changes to the entity. From here you can call the save method, this maps to the update method within the repository. A class is returned containing the updated entity, in the below example I’m popping up a success message in the SPEAK message panel.

UpdateNewsArticle: function () {

 var newsService = new entityService({
 url: "/sitecore/api/ssc/MikeRobbins-News-Controllers/newsarticle"
 });

 var result = newsService.fetchEntity("73e3a4fe-7d42-4ed9-b66e-ad948f340f27").execute().then(function (newsArticle) {
  newsArticle.Title = "Hello World";

 newsArticle.save().then(function (savedNewsArticle) {
 messagePanel.addMessage("notification", { text: "Item updated successfully", actions: [], closable: true, temporary: true });
 });
 });

 },

Delete Entity Example

Create an instance of EntityService with the service url, you can then call the Delete function passing in the entity to delete. This will then call the delete method within your repository defined within the controller.

DeleteNewsArticle: function () {

 var newsService = new entityService({
 url: "/sitecore/api/ssc/MikeRobbins-News-Controllers/newsarticle"
 });

 var itemToDelete= {
 Id: itemId
 };

 var result = newsService.delete(itemToDelete).execute().then(function (newsArticle) {
 });

 },

Create Entity Example

Create an instance of EntityService with the service url. You can then create a new object populating the properties of your entity. From here you can call CreateEntity, passing in the object you created. This will then call the add method within your repository defined within the controller. A class is returned of the newly created entity.

CreateNewsArticle: function () {

 var newsService = new entityService({
 url: "/sitecore/api/ssc/MikeRobbins-News-Controllers/newsarticle"
 });

var exampleNewsArticle = {
 Title: "Hello World",
 Description:"Some content describing the news article.";
}; 

 var result = newsService.createEntity(exampleNewsArticle).execute().then(function (newsArticle) {
var title = newsArticle.Title;
 });

 },

Tools

There is a few tools you can use to help with debugging and exploring SSC.

  1. Fiddler http://www.telerik.com/fiddler
  2. Kevin Obee’s Sitecore Glimpse Plugin. Under Sitecore Tab there is a sitecore services section where you can explore your SSC services.

    Sitecore Glimpse

    Sitecore Glimpse

  3. POSTman https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
  4. Chrome’s Console

Source

I have an example Sitecore SPEAK application with SSC implemented available on GitHub.  https://github.com/sobek1985/SitecoreSPEAKBulkWorkflows/

Sitecore SPEAK: How to add Applications to Sitecore 8 Launch Pad

Sitecore SPEAK’s Launch pad existed within Sitecore 7.1/7.2/7.5 but has received a major overhaul in Sitecore 8. It has become a focal point welcoming users as they login to Sitecore.

Previously with Sitecore 7.x you could add shortcuts to the launch pad from within the Core database. This was done by adding application shortcut items containing the ID of the new Sitecore SPEAK application to the launch pad shortcuts folder. “/sitecore/client/Applications/Launch Pad/Page Settings/Shortcuts”

Sitecore 7.x SPEAK Shortcuts

Sitecore 7.x SPEAK Shortcuts

With Sitecore 8, the configuration of Launch Pad shortcuts has changed. If you are installing existing Sitecore SPEAK modules built on Sitecore 7.x, then you will need to follow these steps to see the shortcuts in the new Launch Pad.

For Sitecore 8 these are the steps to add an application shortcut to the launch pad.

  1. Switch to the core DB in the desktop or use Sitecore rocks.
  2. Navigate to the following item “/sitecore/client/Applications/Launchpad/PageSettings/Buttons”
  3. Here you can create LaunchPad groups to contain your shortcuts.

    LaunchPad Groups and Buttons

    LaunchPad Groups and Buttons

  4. Create a LaunchPad-button within your new group.
  5. Set the Icon, and Text of the shortcut as required. The link field needs to be set to the URL of your Sitecore SPEAK application (This is single link text field)

    SPEAK Application URL

    Sitecore SPEAK Application URL

  6. The Sitecore SPEAK application URL can be taken from the item path in your SPEAK Application item. E.g. “/sitecore/client/MikeRobbins/SitecoreDataImporter”

    Sitecore SPEAK Application Item Path

    Sitecore SPEAK Application Item Path

Web API Sitecore ID Formatter

When using Web API, Sitecore ID’s serialise with {} around the IDs. This can cause issues when working with JSON as this denotes objects encapsulation.

JSON Sitecore ID's

JSON Sitecore ID’s

Below is a custom formatter to format Sitecore item IDs without the {}. This example has Web API registered to run alongside Web Item API.

See Patrick Delancy’s blog post about running Web API alongside Web Item API http://patrickdelancy.com/2013/08/sitecore-webapi-living-harmony/

The corresponding JSON

The corresponding JSON

  public class RegisterWebApiRoute
    {
        public void Process(PipelineArgs args)
        {
            var config = GlobalConfiguration.Configuration;
            config.Routes.MapHttpRoute("DefaultApiRoute",
                                     "mikerobbinsapi/{controller}/{id}",
                                     new { id = RouteParameter.Optional });

            var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
            config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
           config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IDConverter());
        }
    }
public class IDConverter : JsonConverter
   {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(ID);
        }
        public override bool CanRead
        {
            get
            {
                return false;
            }
        }
        public override bool CanWrite
        {
            get
            {
                return true;
            }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var id = (ID)value;
            writer.WriteValue(id.ToString().Replace("{", "").Replace("}", "").ToUpperInvariant());
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // Default reader used
            throw new NotImplementedException();
        }
    }

Sitecore SPEAK Visual Studio Project and Item Templates

To help developers new to Sitecore SPEAK development and speed up development for existing developers, I’ve created some Visual Studio templates. These help to setup new VS projects correctly for SPEAK development and add SPEAK items quickly. Ill be adding more SPEAK Visual Studio templates in the future.

The first is a project template that creates a new project ready to create an SPEAK application.

Sitecore SPEAK Application

Sitecore SPEAK Application

The second allows you to add new PageCode files directly from the add item window.

SPEAK PageCode

SPEAK PageCode

GitHub Releases – Visual Studio application and item templates

https://github.com/sobek1985/SPEAKTemplatesForVisualStudio/releases

GitHub Source Code

https://github.com/sobek1985/SPEAKTemplatesForVisualStudio

Install Solr as Windows Service for Sitecore Content Search

  1. Download and setup Solr for Sitecore
    (Great tutorial from Dan Solovay on this http://www.dansolovay.com/2013/05/setting-up-solr-with-sitecore-7.html)
  2. Download Non Sucking Service Manager from http://nssm.cc/download.
  3. Copy the nssm.exe into your solr directory.

    NSSM

    NSSM

  4. Create a bat file within the Solr/example folder. Example below, where CD is your example folder within your Solr directory.
    @echo off
    cd "C:\solr\example\"
    java -Xms64M -Xmx256M -jar start.jar
    
  5. Run Command Prompt as Admin. CD to the directory containing of your NSSM.exe
  6. Run the following script to install Solr as a service.”nssm install YourDesiredServiceName” “c:/Solr/LocationOfBatScript””E.g. nssm install MikeRobbinsSolr “C:\solr\example\Solr.bat”

    Solr Service Installed

    Solr Service Installed

  7. Start the service from the services snap in

    Solr Services

    Solr Services

 

 

Sitecore SPEAK Uploader Uploaded Item

Quite often when using the Sitecore SPEAK Uploader to upload items to the Media Library, you need to be able to access the item after upload within the JavaScript page code to work with the item.

Below is an example of how to get access to the Media Item model after it has been uploaded into the Media Library.

This method is only supported in Sitecore 7.1 rev. 140324 (7.1 Update-2). I raised this as a bug with Sitecore as Item Id’s weren’t returned, and its been fixed in this release.

  initialize: function () {

   //Subscribe to the "upload-fileUploaded" event of the Uploader. 
   //This is called after each item is uploaded successfully to the media library. 
   //Specify a function to handle the uploaded event.

   this.on("upload-fileUploaded", fileUploaded, this);
  },
var fileUploaded = function (model) {
    // Access the model for the uploaded Media Item.
    var itemId =   model.itemId
};

Write to Web Forms Programmatically

Recently I had a requirement to capture a number of parameters from a users session and provide Sitecore administrators a way of reporting on this data and exporting the data to CSV for analysis.

The reporting within WFFM was exactly what I was looking to achieve. I wondered if I could tap into this programmatically and use WFFM as my analysis and exporting tool.

Form Reports

Form Reports

The idea is to create a new Form within WFFM and instead of adding the form to the page, instead create an instance of the form in memory, complete form and post the data into the WFFM database.

Below is a code sample (commented) of completing the Form and posting the data back programmatically.

public void SubmitToWFFM(ID formID, string username, string anotherString)
{
//Get form item by Item ID
Sitecore.Forms.Core.Data.FormItem formItem = Sitecore.Forms.Core.Data.FormItem.GetForm(formID);

//Get form fields of the WFFM
FieldItem[] formFields = formItem.Fields;

//Get all form fields of the form by name
FieldItem usernameField = formFields .FirstOrDefault(x =&amp;gt; x.FieldDisplayName == &quot;Username&quot;);

FieldItem anotherField = loggingFields.FirstOrDefault(x =&gt; x.FieldDisplayName == &quot;AnotherField&quot;);

//Populate fields with values
ControlResult controlUsernameTerm = new ControlResult(usernameField.Name, username, null);
ControlResult controlAnotherField = new ControlResult(anotherField.Name, anotherString, null);

//Create collection of fields
AdaptedControlResult[] acr = new AdaptedControlResult[2];
acr[0] = new AdaptedControlResult(controlUsernameTerm, false);
acr[1] = new AdaptedControlResult(controlAnotherField, true);

AdaptedResultList arl = new AdaptedResultList(acr);

//Save form
SaveToDatabase dbSave = new SaveToDatabase();
try
{
dbSave.Execute(formId, arl, null);</pre>

catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error(ex.Message, ex, this);
}
}

Sitecore SPEAK Dialog Within Desktop

Here is a short useful tutorial for anyone wanting to add a SPEAK Dialog control within the Sitecore desktop view. Basically it uses a Sitecore sheer ui application as a proxy to point at the url of the SPEAK application.

SPEAK Dialog

SPEAK Dialog

  • Create a Sitecore dialog application using Sitecore rocks within the core database.

    SPEAK Dialog Application

    SPEAK Dialog Application

  • Create a standard application item under content / applications in the core database.Set the application field to an link pointing at the url at the SPEAK application.Example Raw Value: <link url=”/sitecore/client/MikeRobbins/Dialogs/RolePermissions” linktype=”internal” id=”” />

    Application Item

    Application Item

  • Create an application shortcut pointing at the application within the applications folder.<link linktype=”internal” url=”/applications/RolePermissions” querystring=”” target=”” id=”{5DD732CF-67CE-4EF3-9F76-D53E16225693}” bdgtk

    Application Shortcut

    Application Shortcut

An example of this method can be seen in my bulk user permissions module on GitHub https://github.com/sobek1985/SitecoreSPEAKBulkRolePermissions

The next stage is to use this method to create a command button in the content editor and pass in the context item using query string parameters.

Update

I have discovered this method also works in Sitecore 8.

Sitecore 8 SPEAK Dialog

Sitecore 8 SPEAK Dialog

Solr Search On Exact Phrase

Very brief code sample of how to perform a exact phrase match query in Solr.

Using the Solr Admin’s Query tool to perform a search on a field, you will notice that Solr splits each word into a token to search on.

Solr Phrase Match 1

Solr Admin Query

 

Most of the time this is the desired functionality, however there could be times where you want to return results where the exact phrase is matched. If you perform a search wrapping quotes around the phrase within the Solr Admin Query tool, Solr will perform a query looking for an exact match on the phrase (see screenshot below, notice the reduced number of results).

 

Solr Phrase Match 2

Solr Admin Phase Search With Quotes

 

Below is a code sample of how to perform a search using Sitecore 7’s Content Search API’s. The code checks whether the keywords searched upon start and end with quotes. If the quotes are present, the keywords are then passed into the search intact with the quotes present. If the quotes aren’t present the keywords are split into an array on a space and the search is performed as normal.

private Expression<Func<SearchItem, bool>> GetKeywordFilters(string keywords)
 {
 var predicate = PredicateBuilder.True<SearchItem>();

 var keywordCollection = new List<string>();

 if (keywords.StartsWith("\"") && keywords.EndsWith("\""))
 {
 keywordCollection.Add(keywords);
 }
 else
 {
 keywordCollection = keywords.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
 }

 var filters = keywordCollection.Aggregate(predicate, (current, keyword) =>
current.Or(i => (i.Body.Equals(keyword)
 || i.Title.Equals(keyword)
);

 return filters;
 }
public SearchResult<SearchItem> Search(string keywords)
 {

 using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex(_searchIndex).CreateSearchContext())
 {
 var queryable = context.GetQueryable<SearchItem>();

 Expression<Func<SearchItem, bool>> filters;

 filters = GetKeywordFilters(keywords);
 queryable = queryable.Where(filters);

 var results = queryable.GetResults();
 }

Text Based Content Search Based On Tagging

Out of the box Sitecore offers Content Editors the power to create tags, and assign them to content items using the Tagging field in standard values.

Tagging Standard Value

Tagging Standard Value

When analysing the indexes using LUKE, you can see that Sitecore indexes the ID’s of each tag. This makes it difficult to perform a text based content search that also matches on tags.

Luke Index View

Luke Index View

However Sitecore gives us the power to create computed fields in search indexes. This means we can create new fields within the index and programmatically create text into the index.

This example below uses a computed field that instead of indexing the ID of the tag, instead adds the item name of each tag seperated by a space. This then allows you to perform a text based search against the tag. (Sitecore by default indexes the __Semantics field, so here i’m creating a new field in the index called “tags” not to override any standard Sitecore functionality)

 

Computed Field Class

namespace MikeRobbins.CMS.ComputedFields
{
public class Tags : IComputedIndexField
{
public object ComputeFieldValue(Sitecore.ContentSearch.IIndexable indexable)
{
var tags = new StringBuilder();

Item obj = (Item)(indexable as SitecoreIndexableItem);

if (obj != null)
{
var tagField = (Sitecore.Data.Fields.MultilistField)obj.Fields["__Semantics"];

if (tagField != null)
{
var items = tagField.GetItems();

foreach (var item in items)
{
tags.Append(item.Name + " ");
}
}
}

return tags.Length != 0? tags.ToString():null;
}

public string FieldName { get; set; }
public string ReturnType { get; set; }
}
}

XML Config

Add this XML to the “AddComputedIndexField” section of your search index config.

<field fieldName="tags"                           >MikeRobbins.CMS.ComputedFields.Tags,MikeRobbins.CMS</field>
Follow

Get every new post delivered to your Inbox.

Join 211 other followers

%d bloggers like this: