Thursday, 4 October 2018

Sitecore PowerShell Extensions - Custom function

Last time I had to prepare a resolution for making changes on the existing content after the deployment. We were adding new components to Standard Values of the page and they had to be configured properly on the content item by setting data source. Change like this couldn’t be synchronised by Unicorn as the page content item was one-time deployment only item (NewItemOnlyEvaluator) and setting data source straight on Standard Value is a really bad idea!

We had three options there:
  1. Set data source manually after synch
  2. Create a Sitecore content package with prepared changes
  3. Prepare Sitecore PowerShell script that will automate the changes we need
As doing things manually is always error-prone and package could overwrite some content changes, we decided to go for third option – PowerShell scripting!

First of all, I needed a way for setting data source on rendering that already exists on a page content item. I found there is not such specific function in SPE core so I wrote a custom one.





To create a custom SPE function we need to have new module created. The easiest it will be by using wizard:





We will need Shared Functions integration, so we can select it just while creating the module.



It can be done after as well just by creating scripts library called Functions. Here's link to documentation: https://doc.sitecorepowershell.com/modules/integration-points/functions

After this we will have our module folder with Functions folder inside. There we will create our custom shared function.


I have named it Set-RenderingDatasource.  Body of the function should be placed inside field described as Script body - Source code written in PowerShell. That's the function I've shown earlier. 

Next thing will be create new PowerShell Script Library item, just on the same level as Functions item. I named it as After Deploy Scripts and created one new script inside - Apply-Datasources:



This script will use our custom shared function to apply datasources to items. Here is the code:



First crucial thing is to import our shared function

Import-Function -Name Set-RenderingDatasource

Then I have added a flag for rolling back changes if needed. That's a subject of decision how we should do the rollback. For this example rollback will be simply setting empty datasources to that items - as they are empty at beginning.

Under I've added variables that will contain ID of the page where we want make our updates, references to rendering items we want to set datasource and ids of datasources. All those things should be known, as we are assuming they will be deployed by, e.g. unicorn (new renderings and datasources - one time deployment) or they are in the content already for some time - the page we want to update.

Then, based on the rollback flag, I'm using our imported function to set up datasources

Set-RenderingDatasource -Page $updatedPage -Rendering $modalRendering -DatasourceId $modalDatasourceId -Device Default -Publish

 Let's roll now! Let's edit our script in ISE!

And run it to see the result:


It's good to log the things script does and say something at the end of execution.

Done! I hope that was interesting lesson of using Sitecore PowerShell to apply changes after deployments. Enjoy!

Saturday, 19 May 2018

SIF Sitecore 9 installation issue

A couple days ago I came across a problem while installing Sitecore 9.0.2 using SIF:

.Net SqlClient Data Provider: Msg 12809, Level 16, State 1, Line 5
You must remove all users with password before setting the containment property to NONE.

I was using MS SQL Server 2016 (13.0.4001.0). After opening Management Studio I realized that some databases were created already because at first run my script went to some point then failed. So the easy fix go go through this issue was just to remove these databases as they were only partially completed.

Saturday, 7 April 2018

Configuring Unicorn on Helix project

Setting up synchronization in Helix based solution is one of the most crucial things. With proper configuration all new projects will be easy to maintain and predictable. In this short post I will describe basics of configuring Unicorn.

Helix structure configuration

First of all we should have our Foundation.Serialization project configured. In this project we should install Unicorn - from the nuget feed.

We should have whole Helix items structure configuration here and this one should be synched as the first in the queue.


There is unicornSourceFolder variable which should be pointing /src/ folder of our app code. We can specify it for example in some patch in Project.Common project.


 

Abstract configurations

It is really good idea to have some basic configuration we can inherit from. It can be placed in for example Foundation.Serialization project.





Then we can use this abstract configuration in our projects




We do it by using extends parameter

extends="SitecoreCoffee.Base"

If our project is relying on some other, e.g. from Foundation layer, then we should specify it by dependencies parameter. Here it depends on whole Foundation layer by using asterix

dependencies="Foundation.*"

...but it could be as well list of comma-delimited configuration names

dependencies="Foundation.Search,Foundation.Extensions"

As I mentioned earlier, Foundation.Serialization configuration should be synchronized as first, so the our patch should go after that one:

patch:after="configuration[@name='Foundation.Serialization']"

Don't forget to put descriptive name and description attributes too.

Project-specific configurations

In Helix every project which requires some serialized Sitecore items, should have it's own Unicorn configuration. Above we created Feature.Search project configuration and there we put only project-specific items in the predicate

<predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true">
    <include name="SitecoreCoffee.Feature.Search.Templates" database="master" path="/sitecore/templates/Feature/Search" />
    <include name="SitecoreCoffee.Feature.Search.Renderings" database="master" path="/sitecore/layout/renderings/Feature/Search" />
</predicate>

Even if you're not using Helix you should consider creating several small configurations instead of one monolithic. It will be easier to synch only specific ones in Unicorn synch panel.





Monday, 12 March 2018

Using SitecoreController to change page startup

A few days ago I had to implement functionality that will check if external e-commerce system is healthy before any further page processing. I decided to prepare maintenance page in Sitecore and switch to it if there are problems with API. Here the problem appeared - how to make it clean and use already DIed services there?

I could use httpBeginRequest pipeline and put my processor just after Context.Item is resolved. Sounds alright but I wanted to avoid adding unnecessary processors and patches as much as I could.

Then I found really interesting post written by Marek Musielak:

Sitecore Item Controller - the hidden gem of Sitecore MVC https://www.skillcore.net/sitecore/sitecore-item-controller-and-page-rules
I decided I will go with this approach and utilize SitecoreController. Marek described precisely how to set up that new controller and where to refere it in template. Here I will describe how I used it.

Controller setup

My controller will be responsible for checking external commerce health before any rendering and API call is made. It should extend SitecoreController that exists in Sitecore.Mvc.Controllers namespace (Sitecore.Mvc assembly). I'm using there two services - one that wraps context item switching and second one for API calls. I found out that there should be only one parameterless constructor in this controller. Unfortunately then you can't inject services properly - only way is to use service locator antipattern!

Further, you should override Index() method and do your stuff there. I'm calling heartbeat service and if system is dead I'm switching context page item to maintenance page. I'm checking as well if maintenance mode was explicitly set in site settings item. And if we are in Experience Editor we don't want this switching to happen, so I'm checking for that option as well. At the end we need to call base Index() method.

Be aware: heartbeat check action must be fast as Flash or even faster. You don't want to add much more rendering time to page. Sometimes it's even better to do that check on client side, but that's more SPA approach. Just make sure it finishes in desired period of time and even drop the execution if it takes more! You can use async calls and cancellation tokens - here I found some nice article by Dave Paquette you can begin with, but that's surely something outside Sitecore: https://www.davepaquette.com/archive/2015/07/19/cancelling-long-running-queries-in-asp-net-mvc-and-web-api.aspx

Page template setup

As Marek described, we need to bind our controller with template's Standard Values to make it work.

Template using SitecoreController

And that's it, this functionality will run before any rendering start to be processed.


Whole implementation is available on my Helix examples and experiments project on GitHub:

ReoKzK/SitecoreCoffee https://github.com/ReoKzK/SitecoreCoffee/tree/master/src/Feature/Commerce/code