10

When trying to access the Sitecore Configuration Factory to read a setting while configuring services in the IoC container the below exception is thrown.

public class ServicesConfigurator : IServicesConfigurator
{
    public ServicesConfigurator()
    {
        Sitecore.Configuration.Factory.GetConfiguration();
    }
}

I know, that this is because the configuration factory itself is configured in the container, and is not yet available, so the question is, how do I access values from the Sitecore configuration, before the configuration factory is available through the container? Accessing the factory through the Service Locator throws the same exception, eventhough the factory is already registered at this point.

Source Error:

Recursive upgradeable lock acquisitions not allowed in this mode.

Sitecore.Configuration.Factory.GetConfiguration();

Stack Trace:

[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

[TargetInvocationException: Exception has been thrown by the target of an invocation.] System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +138
System.Activator.CreateInstance(Type type, Boolean nonPublic) +105
System.Activator.CreateInstance(Type type) +12
Sitecore.DependencyInjection.ConfiguratorsConfigurator.b__0(XmlNode x) +164 System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +223 Sitecore.DependencyInjection.BaseServicesConfiguratorFactory.Configure(IServiceCollection serviceCollection) +179
Sitecore.DependencyInjection.BaseServicesConfiguratorFactory.Configure(IServiceCollection serviceCollection) +160
Sitecore.DependencyInjection.BaseServiceProviderBuilder.ConfigureServiceCollection() +142 Sitecore.DependencyInjection.ServiceLocator.ConfigureServiceProvider() +256 Sitecore.DependencyInjection.ServiceLocator.get_ServiceProvider() +153 Sitecore.DependencyInjection.SitecorePerRequestScopeModule..ctor() +13

[TargetInvocationException: Exception has been thrown by the target of an invocation.] System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +138
System.Activator.CreateInstance(Type type, Boolean nonPublic) +105
System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) +1499
System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +191 System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) +27
System.Web.HttpRuntime.CreateNonPublicInstance(Type type, Object[] args) +82
System.Web.HttpApplication.BuildIntegratedModuleCollection(List`1 moduleList) +229
System.Web.HttpApplication.GetModuleCollection(IntPtr appContext) +1114 System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +140
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +402
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +343

[HttpException (0x80004005): Exception has been thrown by the target of an invocation.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +539
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +125 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +731

3
  • Why are you doing this in the constructor? There's a Configure method you're supposed to use: doc.sitecore.net/sitecore_experience_platform/developing/… Commented Mar 21, 2017 at 9:42
  • That was just an example actually, accessing the configuration factory in the Configure method gives the same result.
    – Kasper
    Commented Mar 21, 2017 at 9:49
  • Ideally, what I wanted, was to set properties on the ServicesConfigurator, similar of how you can set properties through the Configuration Factory, but this is not available when configuring services configurators.
    – Kasper
    Commented Mar 21, 2017 at 9:56

1 Answer 1

10

Explanation

Your configurator is run as a part of the DI container initialization. During that phase, you cannot use the Sitecore Factory, because, starting from Sitecore 8.2, Factory uses the DI container under the hood. This restriction is apparently there to prevent configuration loops: container requests something from the Factory, the Factory falls back to the not-yet-initialized container, and so on.

Because of this, you cannot:

  • Access Sitecore configuration when initializing the container;
  • Instantiate objects using the Factory from your configurators;
  • Inject properties or constructor parameters into the configurator itself.

Suggestions

If you need to get parts of DI configuration from a file, you can:

  • Read settings from your own configuration file (without using Sitecore Factory);
  • Use appSettings / applicationSettings in the Web.config;
  • Substitute the underlying DI container with something that supports custom configuration file format, such as Autofac;
  • Use configuration-level injection of an implementation of a certain interface. That specific implementation will provide the settings — this way, settings are still set in the code, but are easily swappable from XML configuration.
1
  • 1
    This sums up my findings, so I guess what I am trying to accomplish is not possible. For now I will go with "configuration through code" and hardcode the needed values. Maybe I will explore alternative approaches later on.
    – Kasper
    Commented Mar 21, 2017 at 11:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.