---
title: Dependency injection
slug: cms-13/docs/dependency-injection
createdAt: 2026-07-30T20:22:01.166Z
---

Dependency injection (DI) in Optimizely Content Management System (CMS) is based on the DI framework in ASP.NET Core located in [Microsoft.Extensions.DependencyInjection](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1) API. CMS is configured to use the default DI implementation in ASP.NET Core. The required code in `Program.cs` to connect the DI framework in ASP.NET Core with CMS is the call to the extension method `ConfigureCmsDefaults()` as in the example below:

```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)
  .ConfigureCmsDefaults()
  .ConfigureWebHostDefaults(webBuilder => {
    webBuilder.UseStartup<Startup>();
  });
```

If your PaaS application uses `AddCms()` in `Startup.ConfigureServices`, Content Manager is not auto-registered. You must add it explicitly:

```csharp
public void ConfigureServices(IServiceCollection services) {
  services.AddCms();
  services.AddContentManager();  // Required for PaaS in v13.0.0-preview3+
}
```

## Custom dependency injection frameworks

To use a different DI framework than the built-in, replace the call to `ConfigureCmsDefaults()` with a call to `UseServiceProviderFactory`, passing an instance of `ServiceLocatorProviderFactoryFacade` that encapsulates the implementation. The following example configures the application to use Autofac (given that there is a reference to the Autofac NuGet package):

```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)
  .UseServiceProviderFactory(context =>
    new ServiceLocatorProviderFactoryFacade<ContainerBuilder>(context,
      new AutofacServiceProviderFactory()))
  .ConfigureWebHostDefaults(webBuilder => {
    webBuilder.UseStartup<Startup>();
  });
```

## Implicit registration of services

The following example uses implicit registration with the `ServiceConfiguration` attribute. The registration is done in the same class as the implementation. The code registers a service as a transient service (instances are created every time) or as a singleton service (a single instance is reused).

```csharp
public interface IService {
  void Sample();
}
[ServiceConfiguration(ServiceType = typeof (IService))]
public class TransientService: IService {
    public void Sample() {
      throw new NotImplementedException();
    }
  }
  [ServiceConfiguration(ServiceType = typeof (IService), Lifecycle = ServiceInstanceScope.Singleton)]
public class SingletonService: IService {
  public void Sample() {
    throw new NotImplementedException();
  }
}
```

## Explicit registration of services

The following code registers `IService` and its implementation Service using the `IServiceCollection` abstraction. Service registrations are done in the `Startup` class or in an extension method like `AddCms`. The service registration abstraction is also available in initialization modules that implement the `IConfigurableModule` interface. There are convenient extension methods in namespaces `Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.DependencyInjection.Extensions` and `EPiServer.ServiceLocation`. Inline comments describe the examples in more detail:

```csharp
[InitializableModule]
public class ModuleWithServices: IConfigurableModule {
  public void ConfigureContainer(ServiceConfigurationContext context) {
    // Register IService with implementation Service, 
    // create new instance every time 
    context.Services.AddTransient<IService, Service>();

    // Register IService with implementation Service, 
    // reuse a single instance 
    context.Services.AddSingleton<IService, Service>();

    // Register IService with custom factory 
    context.Services.AddTransient<IService>((locator) => new Service());

    // Register IService to be cached per scope, 
    // for example, HTTP request 
    context.Services.AddScoped<IService, Service>();
  }
  public void Initialize(InitializationEngine context) {}
  public void Uninitialize(InitializationEngine context) {}
}
```

## ServiceLocator

Use dependency injection through constructors or use the DI container from a context like `HttpContext.RequestServices`. Use a static property `ServiceLocator.Current` to access the DI container when no other way to get dependencies. If you use `ServiceLocator.Current` with custom scopes, create the scopes using extension method `CreateServiceLocatorScope` instead of the extension method `CreateScope` within .NET Core. This makes the static accessor `ServiceLocator.Current` aware of the custom-created scope.

## Intercept existing services

To intercept service calls, use the extension method `Intercept<T>` on `IServiceCollection`, to replace existing services with another implementation. The provided factory method will have access to the default instance of the service.

If several implementations are registered for a service, the interceptor intercepts all registrations. The interceptor service has the same scope as the intercepted service .

The following example intercepts the `ISynchronizedObjectInstanceCache` registration, where the interceptor logs remote removals.

```csharp
using EPiServer.Framework;
using EPiServer.Framework.Cache;
using EPiServer.Framework.Initialization;
using EPiServer.Logging;
using EPiServer.ServiceLocation;
using System;

namespace EPiServerSamples {
  [ModuleDependency(typeof (EPiServer.Web.InitializationModule))]
  public class LoggingInitializer: IConfigurableModule {
    public void ConfigureContainer(ServiceConfigurationContext context) {
      context.Services.Intercept<ISynchronizedObjectInstanceCache>(
        (locator, defaultCache) => new LoggingSynchronizedCache(defaultCache));
    }
    public void Initialize(InitializationEngine context) {}
    public void Uninitialize(InitializationEngine context) {}
  }
  public class LoggingSynchronizedCache: ISynchronizedObjectInstanceCache {
    private readonly ISynchronizedObjectInstanceCache _defaultCache;
    private readonly ILogger _log = LogManager.GetLogger(typeof (LoggingSynchronizedCache));
    public LoggingSynchronizedCache(ISynchronizedObjectInstanceCache defaultCache) {
      _defaultCache = defaultCache;
    }
    public void RemoveRemote(string key) {
      if (_log.IsDebugEnabled())
        _log.Debug($"Remote removal called at '{DateTime.Now}' with key '{key}'");
      _defaultCache.RemoveRemote(key);
    }
    public IObjectInstanceCache ObjectInstanceCache => _defaultCache.ObjectInstanceCache;
    public FailureRecoveryAction SynchronizationFailedStrategy {
      get {
        return _defaultCache.SynchronizationFailedStrategy;
      }
      set {
        _defaultCache.SynchronizationFailedStrategy = value;
      }
    }
    public object Get(string key) => _defaultCache.Get(key);
    public void Insert(string key, object value, CacheEvictionPolicy evictionPolicy) => _defaultCache.Insert(key, value, evictionPolicy);
    public void Remove(string key) => _defaultCache.Remove(key);
    public void RemoveLocal(string key) => _defaultCache.RemoveLocal(key);
  }
}
```
