Sitecore 9 Configuration not available on Dependency Injection – LockRecursionException: Recursive upgradeable lock acquisitions not allowed in this mode

Form Sitecore 8.2, Sitecore have implemented Dependency Injection for their own classes. Sitecore uses Microsoft’s Dependency Injection library.

Sitecore uses dependency injection to inject many things, including configurations. Therefore, you cannot access configuration before after your code have been injected.

Take the following example:

using Sitecore.Configuration;

namespace MyCode
{
  public class ServicesConfigurator() : IServicesConfigurator
  {
    public void Configure(IServiceCollection serviceCollection)
    {
      // This line will fail:
      var configuration = Factory.GetConfiguration();
      serviceCollection.AddTransient<MyClass>();
    }
  }
}

This code will thrown an error:

[LockRecursionException: Recursive upgradeable lock acquisitions not allowed in this mode.]
System.Threading.ReaderWriterLockSlim.TryEnterUpgradeableReadLockCore(TimeoutTracker timeout) +3839391
System.Threading.ReaderWriterLockSlim.TryEnterUpgradeableReadLock(TimeoutTracker timeout) +45
Sitecore.Threading.Locks.UpgradeableReadScope..ctor(ReaderWriterLockSlim mutex) +107
Sitecore.DependencyInjection.ServiceLocator.get_ServiceProvider() +85 Sitecore.Configuration.Factory.<.cctor>b__0() +9
System.Lazy1.CreateValue() +709 System.Lazy1.LazyInitValue() +191 Sitecore.Configuration.Factory.GetConfiguration() +44

The implications is that none of your injected constructors can contain references to:

  • Databases
  • Site information
  • Settings

HOW TO WORK AROUND INJECTED CODE WITH CONSTRUCTORS:

Imaging you like to inject a repository with the Sitecore Database as a constructor. You also would like to inject the database of the current context.

First you create an interface:

using Sitecore.Data;

public interface IDatabaseFactory
{
  Database Get();
}

Then you create a concrete implementation of the interface:

public class ContextDatabaseFactory :IDatabaseFactory
{
  public Database Get()
  {
    return Sitecore.Context.Database;
  }
}

In the ServicesConfigurator you can now register the abstract implementation:

public class ServicesConfigurator : IServicesConfigurator
{
  public void Configure(IServiceCollection serviceCollection)
  {
    // The database factory to inject:
    serviceCollection.AddTransient<IDatabaseFactory, ContextDatabaseFactory>();
    // The class that needs the database in the constructor:
    serviceCollection.AddTransient<MyRepository>();
  }
}

And in the MyRepository you reference the IDatabaseRepository in the constructor instead of the concrete Sitecore Database implementation:

public class MyRepository
{
  private readonly IDatabaseFactory _database;
  
  public MyRepository(IDatabaseFactory database)
  {
    _database = database;
  }
  
  public void DoTheActualCode()
  {
    _database.Get().GetItem("/sitecore/content/...");
  }
}

Many thanks to my cool colleagues who helped forge this solution:

MORE TO READ:

 

Advertisements

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in .net, c#, General .NET, Sitecore 8, Sitecore 9 and tagged , , , . Bookmark the permalink.

One Response to Sitecore 9 Configuration not available on Dependency Injection – LockRecursionException: Recursive upgradeable lock acquisitions not allowed in this mode

  1. Pingback: Sitecore 9 Dependency Injection – Extend the Sitecore Logging | Brian Pedersen's Sitecore and .NET Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.