Adding Items to a Custom Sitecore Seach Index using SiteCron

old-books

Over the years working with Sitecore I’ve had to create custom indexes and add items to them for most clients I’ve worked for. I’ve generally written a Search Crawler and Search Indexer to handle this but it’s always seemed like a lot of code to manage just to add a few items to an index and temperamental to control the indexing frequency accurately. I’ve also had many issues with Indexes being out of Sync in the past due to Sitecore Events not firing on CD instances etc.

I’ve tried various approaches to simplifying this in the past but unfortunately never got this working. However this came up again on a recent project and I was successful this time – so decided I’d share my approach and code.
Note in this example I’m using Solr but in Theory this same code should work with Azure Search also.

In simple terms the approach is to:

1) Create a Custom Index – to store my content (in this case Blogs)
2) Create a Search Indexing Service – which will retrieve the Items and add them to the Custom index
3) Create an SiteCron Indexing Job – which will call my Indexing Service to Index the Items on a regular basis
4) Create a Search Results Page – which will display the search results from the Index

Benefits of this approach

  • Less Code to write and manage
  • Can control how often the indexing runs very accurately (using SiteCron) and this persists across App Service / IIS Restarts.
  • Easy to test and maintain

1) Creating a Custom Solr Index

I’m not going to go into this process too much as it’s documented well elsewhere but essentially you need to copy on of the out of the box solr folders, rename it and also update the core.properties file. For this example I’ve created and index called sc93_blogs_index:

custom-index-folder

Configuration

You will also need to add 2 configuration files for the custom Index like so to define the index name, strategy (of manual) and configure the fields to include. Amend these as required for your use-case:

Index Config:
Index Fields Config:

 

2) Search Indexing Service

The next step is to create our Search Indexing Service. This will get the blog items and add them to the index. This could easily be pulling Info from an datatabase, API or File instead if needed.  I’ve called mine BlogPostSearchService:

 public class BlogPostSearchService : ISearchService
 {
  ...
 }

I also added an interface with  two methods:

public interface ISearchService
{
   int IndexContent();

   BlogPostSearchResultsModel GetResults(BlogPostSearchResultsModel blogPostSearchResultsModel, string searchTerm, int resultsPerPage, int currentPage);

}

Index Content Method

The IndexContent() Method is like so. Note this code is not optimal if you have more than a few hundred items within a folder, you may wish to re-structure your items differently:
 

Get Content Method

The GetContent() Method is as follows:

Supporting Models / Classes

There are various supporting models and classes used in the above code. Below are the key ones.

BlogPostSearchResult

My Blog Posts just have two additional properties so this is pretty simple:
public class BlogPostSearchResult: SearchResultItem
{
    [DataMember]
    [IndexField("Title")]
    public string Title { get; internal set; }

    [DataMember]
    [IndexField("Description")]
    public string Description { get; internal set; }
}

BlogPostSearchResultsModel

This Model is used to hold my search results and some other properties about the search results for use in the View:

public class BlogPostSearchResultsModel
{
    public string SearchTerm { get; set; }
    public IPagedList<BlogPostSearchResult> SearchResults { get; set; }
    public int TotalNumberOfResults { get; set; }
    public int NoOfResults { get; set; }
    public int Page { get; set; }
}

Settings

You will notice there are some settings used in the code such as for the Blog Post Items Path. Add a Sitecore patch file for these and configure them as needed.

Paged List

I’m using an Nuget Package for PagedList, this is a good one if you want to use one too: https://github.com/dncuug/X.PagedList

3) SiteCron Indexing  Job

The next step is to create our SiteCron Job which will be responsible for indexing the content. This calls the IndexContent() method on the service. Obviously this needs to match your SiteCron Job name above.
See my post here about logging to the last run log etc if you’d like to do that too.

  This is then setup in SiteCron to run like so, schedule it to run as needed: sitecron-job 

4) Search Results Page

The last step is to display the Search Results. Create a page in Sitecore using whatever template you use. Then Create an Controller Rendering and View in Sitecore, reference the Controller below and add the rendering to the page.

Controller

The Controller looks like so:

View

The View, this is a simplified version:

The Result

So once you’ve done all the above you should end up with something like the following:

search-results-page-blogs

 

Hopefully this helps someone else who need to implement a custom search and illustrates an alternative approach that could work for them.

Installing SiteCron through NuGet and Configuring

watch-header2Last week I needed to run a Job to perform a daily task within Sitecore so I decided that SiteCron would be the perfect fit for this. SiteCron allows you to run Jobs on a schedule within Sitecore using Cron expressions (under the hood it uses Quartz.NET). I’ve used SiteCron on 3 or 4 projects in the past and really like how reliable and configurable it is for these kind of requirements.

Each time I install it though I forget the steps (especially if doing it via NuGet) so I thought I’d give an overview of this below, including the Unicorn config I used.

Wait, where is the SiteCron version for Sitecore 9+?

Unfortunately the latest version at the time was 3.4 which was compiled against .Net 4.5.2 for Sitecore 7 – 8.3.
The client I was working with use Sitecore 9.3 which requires .Net 4.7.1.
So I compiled a new version (3.5) from the Source on Github for Sitecore 9.3 and created a Nuget package. I noticed that João Neto had also created a branch with an upgraded version that should work with Sitecore 10.1 so created a NuGet package for that too (3.6). Akshay (who created SiteCron) kindly uploaded them to NuGet for me.

sitecron-tweet

What version of SiteCron should I use and How do I install it?

You can download Sitecron from the Marketplace however only 3.2 is released there currently. So I’d advise you install it from Nuget instead. Also generally this is a better way to manage the installation and deployment of Modules in Projects.

Here are the versions of SiteCron you should install for each Sitecore version:

  • Sitecore 7-8.2 –> use SiteCron 3.4
  • Sitecore 9.1-9.3 –> use SiteCron 3.5
  • Sitecore 10.1 –> use SiteCron 3.6

    What about Sitecore 9.0 and 10.0?
    – well 3.4 might work with Sitecore 9 and 3.6 may work with Sitecore 10 but I’m not sure, I’ve not tested them.
    If you try them and they don’t work please pull the source, update the .Net version and compile one or let me know and I’ll try and help.

Install Process via NuGet and Unicorn

  1. Within the project you want to install Sitecon in, either use the NuGet package manger in Visual Studio or run the Install-Package command with the version you need:
    Install-Package SiteCron -Version 3.5.0
  2. Once you’ve installed the package you will see the following have been installed in your project:
    +---App_Config
    | \---Include
    | \---Z.SiteCron
    | SiteCron.config
    | SiteCronJobs.config
    | 
    +---sitecore
    | \---admin
    | SiteCron.aspx
    | 
    \---SitecorePackage
     Konabos.Minions.RunMinion.dll
     Konabos.Minions.RunMinion.Help.txt
     SiteCron FULL Sitecore Package.zip
     SiteCron Items Only Sitecore Package.zip

    You should see there are two packages installed from NuGet along with some config, dlls and an admin page.

  3. Next I’d recommend installing the ‘SiteCron Items Only Sitecore Package.zip’ on your local Sitecore instance. This will install just Sitecore items that are required to run the module but no other files.install-sitecron-items-only-package
    Once you’ve installed the package you should see something like the following:
    sitecron-after-install
  4. Next, if your using Unicorn you should configure settings similar to below to ensure the items you just installed get Serialized to disk and deployed to other environments. Were using Helix Base but if you are not the config will be quite similar to the below.

    After completing step 7 below you should serialize this config from the Unicorn control panel once it’s deployed locally.
  5. Review the settings in /Z.SiteCron/SiteCron.config and adjust as required.

  6. Tidy up – you can now remove the Sitecore zip packages from the project and if you are not using Commerce you can remove the Minion dlls too.
  7. Build and publish the Project.
  8. Finally enable one of the sample Jobs that are installed in the OOTB folder and check that it runs correctly. If it does not run then Check the logs.

Creating Custom Jobs using SiteCron

Akshay has written some info on creating Jobs and using it like this one here. I’ve written a few posts before on this too so check them out.

Contributing to SiteCron

If you’d like to contribute to the module then I’m sure Akshay would appreciate it. You can pull the source from here: https://github.com/akshaysura/Sitecron and branch it and then create a pull request.

Note that the active branch is master and that the current code-base has been updated for 10.1. Therefore if you are looking to update the code for an older version of Sitecore then you may need to branch from an older commit to master instead. It’s probably best to reach out to Akshay to be sure.

Once you’ve created an updated version of the Module make sure you also update the AsemblyInfo.cs file with the new version number. You can then run the following command to create a NuGet package and share it with Akshay too:

nuget pack Sitecron.csproj -version 3.7.0

 

Hopefully this is useful for anyone working with SiteCron in future and I’ll aim to update this for future releases if required.

Logging to the SiteCron Last Run Log

time

I’ve worked with SiteCron quite a bit, but up until recently I hadn’t realised until recently that there was a field that should be used to track what happened when the Cron Job last ran, this field is the ‘Last Run Log’.

I think it’s been around since version 2.18 but I didn’t notice it and couldn’t find any examples online which showed me how to use it:

cron-job-log

 

 

 

 

 

 

 

 

I wasn’t sure how to update it but as It is a Multiline text field I figured I could just be update it like any other Sitecore field like so:

The script is pretty simple, it gets the Job Item and then finds the field and updates it. Thankfully SiteCron has some constants that can be used to help here.

Notice how I’m appending to the field to build up an historic log of each run. This is useful if you have a job that runs multiple times a day/week and need to look back at the last x runs to see what happened.
I’m logging both successful and unsuccessful runs. Obviously you can change the log message to say what you want.

Anyway I hope this is useful to others using SiteCron who want to log what the Job does when it runs.