Sunday, 20 October 2019

Helix Publishing Pipeline - file locks issue on deploy

On my last project when I was implementing Helix Publishing Pipeline I found really bizarre issue. Almost every time I was deploying code by publishing it from Visual Studio, some dlls were locked by w3wp process.

No surprise IIS uses those assemblies but I didn't have such locking problem earlier.

I was digging for hours in the Internet and I found out that IIS uses assembly shadowing. So basically it doesn't use directly dlls from webroot bin, but from its the temp folder.

It can be disabled by this setting

<hostingEnvironment shadowCopyBinAssemblies="false" />

When I set this for test, file locks were all over the place.

Earlier I used Process Explorer and I saw that w3wp locks not only shadowed dlls but as well those from webroot bin, so something was not right there!



More digging eventually gave me information that our issue was self-inflicted: https://stackoverflow.com/a/28019475

In GlassMapperScCustom assemblies were loaded by invoking method
Assembly.LoadFile(assemblyPath) 

which loads exact assemblies and it doesn't take into account shadows.

Instead of that we should always use

Assembly.LoadFrom(assemblyPath) 

which loads shadows as it should be.

That fixed issue with file locks for good!

Tuesday, 19 February 2019

Azure Search provider - Results ordering issue

I was implementing Azure Search lately into my last project and I found some strange issue in the provider (we're using Sitecore 9.0.2 rev. 180604). When I wanted to order my search results using Linq like this:

searchQuery.OrderBy(x => x.JobRole).ThenBy(x => x.LastName)

it was translated to:

$orderby=last_name_s,job_role_i

So it looks like it's taking argument of ThenBy as first and OrderBy as the second. Inverting parameters:

searchQuery.OrderBy(x => x.LastName).ThenBy(x => x.JobRole)

gave me desired query:

$orderby=job_role_i,last_name_s

And search result as well were sorted like I wanted.

Azure Search documentation states nothing unusual, but I had to confirm this:


$orderby=[string] (optional)

A list of comma-separated expressions to sort the results by. When calling via POST, this parameter is named orderby instead of $orderby. Each expression can be either a field name or a call to the geo.distance() function. Each expression can be followed by asc to indicate ascending, and desc to indicate descending. The default is ascending order. Ties will be broken by the match scores of documents. If no $orderby is specified, the default sort order is descending by document match score. There is a limit of 32 clauses for $orderby.
https://docs.microsoft.com/en-us/rest/api/searchservice/search-documents#orderbystring-optional

I have raised an issue on Sitecore Helpdesk and guys from support checked and reported the issue. It has a reference number 309333. Current resolution is to invert parameters like I did.


Sunday, 2 December 2018

Unicorn - disabling automatic items serialization

I've come across a problem with Unicorn last time. We deployed to QA environment and a couple days later testers started to see issues like this:

Unicorn: You cannot have a sparse serialized tree

It was appearing when they were saving edited content. I've decided that we don't really need automatic items serialization on QA and other environments, so it will be best to just switch it off. I took a look into Unicorn.DataProvider.config and the comment there states:

This file configures the Unicorn data provider. The data provider writes updated serialized items to disk when they are changed.
This file should be removed in ANY deployed instance (CE or CD) that does not act as a source for serialized item updates.
Generally speaking that's anywhere other than a developer workstation, so your CI process (you have one, right?) should remove this file during the build.
IMPORTANT EXCEPTION: If you are using Transparent Sync as a deployment mechanism, this file must remain on your CE environment.

That's exactly why it should be turned off on any non-development environments.

As we are using Sitecore 9, we have set localenv variable to Local on our dev instances Web.config

<add key="localenv:define" value="Local" />

Instead of removing Unicorn.DataProvider.config config file after deployment, I have added localenv:require="Local" to root element there:

<sitecore localenv:require="Local">
  <dataProviders>
    <!--
      Register the Unicorn data provider for use. If a database hooks to the Unicorn data provider it will
      automatically write changes to the database that match any configured predicate into the serialization provider.
 
      Changes that only affect Revision, Modified, or any fields ignored by FieldPredicates will be ignored.
    -->
    <unicorn type="Unicorn.Data.DataProvider.Unicorn$(database)DataProvider, Unicorn">
      <param connectionStringName="$(1)"/>
      <Name>$(1)</Name>
    </unicorn>
  </dataProviders>
 
  <!--
    Hook the Unicorn Data Provider into the master and core databases. If you're not
    syncing anything in core you can safely unregister it from here. If you want to
    sync something to another database register it here.
 
    It's safe to remove this config section on any environment where you are not
    collecting item changes, which may mean anywhere other than local development
    sites. This will avoid any performance hit from writing unused serialized files.
  -->
  <databases>
    <database id="master">
      <dataProviders>
        <dataProvider ref="dataProviders/main">
          <patch:attribute name="ref">dataProviders/unicorn</patch:attribute>
        </dataProvider>
      </dataProviders>
    </database>
    <database id="core">
      <dataProviders>
        <dataProvider ref="dataProviders/main">
          <patch:attribute name="ref">dataProviders/unicorn</patch:attribute>
        </dataProvider>
      </dataProviders>
    </database>
  </databases>
</sitecore>

That makes sure the changes made by editors won't be serialized.

Saturday, 17 November 2018

Renderings static binding

Last time I had to prepare a component which behaves like a carousel of specific type of renderings. Instead of copy-pasting the Razor markup or using basic Razor partials I decided to use static binding of renderings - method I've never used before. It appeared to be extremely handy.

Basically you can specify a rendering like this:

@Html.Sitecore().Rendering("{ rendering ID }", new { Cacheable = true, Cache_VaryByData = true, DataSource = "{ DataSource ID}" })

First parameter is rendering ID, second is anonymous object where we can specify additional properties, like caching or even datasource that will be used there.

You can even add your custom properties and read them inside rendering, just like this:

@Html.Sitecore().Rendering(
    Constants.MyRendering.RenderingId.ToString("B"),
    new
    {
        Cacheable = true,
        Cache_VaryByData = true,
        DataSource = myDatasource.Id.ToString("B"),
        MyProperty = "My custom value"
 })

To be more familiar with possible properties of that anonymous object I have decompiled GetRendering method from SitecoreHelper class:


I have created and extension method to easily retrieve rendering properties:

And you can use it in view like this:

var property = Html.Sitecore().GetRenderingProperty("MyProperty");


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!

Tuesday, 11 September 2018

Sitecore Module - Dynamic Sitemap XML version 2.0

I have released updated and rewritten version of my Dynamic Sitemap XML module.Version 2.0 comes with better structure of the code and gives much more flexibility in extending it. Now it uses Sitecore Web index by default to improve the performance.

Whole code is hosted on GitHub just like before at https://github.com/ReoKzK/Sitecore.SharedSource.DynamicSitemap.


It can be added to solution by nuget package:

Install-Package Sitecore.SharedSource.DynamicSitemap -Version 2.0.0

Tuesday, 21 August 2018

HelixComponents - Gallery of frequently used website modules

I have released first part of my HelixComponents project. It's aim is to create reusable components that can be used across Helix-based projects.


Each module will be released as a separate repository, which is basically a Helix project. All of them can be taken from my repo at Github: https://github.com/ReoKzK/HelixComponents.
It is based on Helixbase and contains all of these modules.

Here are the first projects:

HelixComponents.Feature.Recommended

Contains modules used for content promotion

HelixComponents.Feature.Tabs

Tabs components - Work in progress

Soon I'm going to release more and fix any outstanding issues