Passing Params to the ServicesConfigurator for DI in Sitecore

pexels-malte-luk-1397751

We are using the IServicesConfigurator interface to configure our services from code and registering it in the <services> section in the Sitecore config. However I had a situation where I wanted to pass some configuration values (to do with a custom cache) to the ServicesConfigurator in order to do something different.

This was my ServicesConfigurator class before I made any changes:

public class MvcControllerServicesConfigurator : IServicesConfigurator
{
  public void Configure(IServiceCollection serviceCollection)
  {
   serviceCollection.AddMvcControllers("*.Feature.*");
   serviceCollection.AddClassesWithServiceAttribute("*.Feature.*");
   serviceCollection.AddClassesWithServiceAttribute("*.Foundation.*");

   //get my param values here
  }
}

This was the config for the pipeline:

       

Normally in Sitecore pipelines we can just set Params in the config of the Pipeline (e.g <useMyCustomCache>true</useMyCustomCache>) and grab them within the pipeline class like so:


public class MvcControllerServicesConfigurator : IServicesConfigurator
{
 public string UseMyCustomCache { get; private set; }
 public void Configure(IServiceCollection serviceCollection)
 {
  ...

  if(bool.Parse(UseMyCustomCache)){
    //do something here
  }
  ...

 However the this doesn’t work and causes an error like so:

[LockRecursionException: A read lock may not be acquired with the write lock held in this mode.] System.Threading.ReaderWriterLockSlim.TryEnterReadLockCore(TimeoutTracker timeout) …

Ok so How do I make this work?

It seems the issue is that Sitecore’s configuration Factory is not available at this point in the initialisation of Sitecore (as it’s also injected with DI). Therefore you can’t do this and you also can’t read any settings using it either (e.g: Settings.GetSetting(“useMyCustomCache”)). So I stumbled across this really useful post with a solution to this using the ConfigReader instead, and it works perfectly. This is my updated ServicesConfigurator code:  

public class MvcControllerServicesConfigurator : IServicesConfigurator
{

 public void Configure(IServiceCollection serviceCollection)
 {
  serviceCollection.AddMvcControllers("*.Feature.*");
  serviceCollection.AddClassesWithServiceAttribute("*.Feature.*");
  serviceCollection.AddClassesWithServiceAttribute("*.Foundation.*");
  
  var useMyCustomCacheNode = Sitecore.Configuration.ConfigReader.GetConfiguration().SelectSingleNode("sitecore/services/configurator/param[@desc='useMyCustomCache']");

 var useMyCustomCache = useMyCustomCacheNode != null ? useMyCustomCacheNode.InnerText : "false";


  if(bool.Parse(useMyCustomCache)){
    //do something here
  }
  ...

This is the final config which follows the same format as a number of Sitecore Pipelines which uses the param format:

Hopefully this useful to anyone else who needs to do this.

As usual there were some really helpful blog posts I found related to this:

https://smartsitecore.com/en/additional-configuration-in-sitecore-pipeline-process/

https://briancaos.wordpress.com/2010/12/10/parameters-in-sitecore-pipelines/

http://sitecore-community.github.io/docs/documentation/Sitecore%20Fundamentals/Sitecore%20Configuration%20Factory/#config_factory

https://kamsar.net/index.php/2016/08/Dependency-Injection-in-Sitecore-8-2/

https://trnktms.com/2021/02/16/getting-sitecore-configuration-from-service-configurator/