---
title: Decorating system services
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

The [decorator pattern](https://refactoring.guru/design-patterns/decorator) allows you to add new functionality to an existing object without altering its structure. There are two main ways the decorator pattern can be implemented in Xperience.

- [Using dependency injection](#decorate-services-via-dependency-injection)
- [Using inheritance](#decorate-services-via-inheritance)

## Decorator pattern considerations

This section provides general guidelines and recommendations for when to use the decorator pattern.

Consider using the decorator pattern when:

- extending an existing implementation with new logic while maintaining the original behavior
- replacing the implementation of specific members, leaving others unchanged

Avoid using the decorator pattern when:

- completely replacing the implementation of a service class – there is no point in decorating a class if you don't plan on reusing any of the logic

## Decorate services via dependency injection

Xperience service classes registered within the ASP.NET Core application's Inversion of Control (IoC) container can be decorated by registering a new implementation of the same service (interface) with a constructor dependency on itself. The service container is capable of resolving the previous implementation of the service from within the new one, allowing you to add custom logic to the service's members.

The benefits of this approach are:

- the service maintains its behavior, but with added custom logic (e.g., additional logging)
- the new implementation gets used in place of the old one automatically across the system
- to revert back to the previous implementation, you only need to stop registering the new implementation into the container
- opens `sealed` and `internal` service implementations for modification
- the IoC container always resolves the _previous_ implementation of a service (last registered relative to the implementation being resolved), allowing you to chain multiple decorators

> **Info:** **Registering multiple decorators for a service from the same assembly**
>
> Service registrations from within the same assembly are nondeterministic – the order of registration can be different every time the application starts. If you need to chain multiple decorators from within a single assembly, you can do so via a [custom code-only module](https://docs.kentico.com/13/custom-development/adding-custom-assemblies.md) class. Override the module's `OnPreInit` method, and call `Service.Use<TService, TImplementation>()` for each of your implementation in the order of dependency. This ensures a deterministic order for the IoC container.

### Example

The following example demonstrates decoration via dependency injection:

1. Create a new implementation of the desired service. This example modifies `IEventLogService` to add more information to the application's event logging.
   - For best practices about integrating custom code, see [Adding custom assemblies](https://docs.kentico.com/13/custom-development/adding-custom-assemblies.md).
2. Inject the same service via a constructor dependency. When instantiating your service, the container resolves its previous implementation.

   ```csharp

   using CMS.Core;

   public class EventLogServiceCustomized : IEventLogService
   {
       private readonly IEventLogService eventLogService;

       // Resolves to the previous implementation of the service
       public EventLogServiceCustomized(IEventLogService eventLogService)
       {
           this.eventLogService = eventLogService;
       }
   }

   ```
3. Implement the methods prescribed by the interface. To keep the original behavior, call the equivalent methods from the injected service within the corresponding method implementations. Add custom logic as required.

   <!-- dev-model:mvc start -->

   **MVC 5 development model.** Applies only when building with ASP.NET MVC 5. If this page also covers ASP.NET Core, that version is in its own block.

   ```csharp

   using CMS.Core;
   using CMS.Helpers;

   public class EventLogServiceCustomized : IEventLogService
   {

       private readonly IEventLogService eventLogService;

       public EventLogServiceCustomized(IEventLogService eventLogService    )
       {
           this.eventLogService = eventLogService;
       }

       public void LogEvent(EventLogData eventLogData)
       {
           // Added custom logic that modifies the logged event data      
           eventLogData.EventDescription += $" Action was performed from {RequestContext.UserHostAddress}";
           // Call to the previous implementation of the method to do the actual logging
           eventLogService.LogEvent(eventLogData);
       }
   }

   ```

   <!-- dev-model:mvc end -->

   <!-- dev-model:core start -->

   **ASP.NET Core development model.** Applies only when building with ASP.NET Core. If this page also covers MVC 5, that version is in its own block.

   ```csharp

   using Microsoft.AspNetCore.Http;

   using CMS.Core;

   public class EventLogServiceCustomized : IEventLogService
   {      

       private readonly IEventLogService eventLogService;
       private readonly IHttpContextAccessor httpContextAccessor;

       public EventLogServiceCustomized(IEventLogService eventLogService,
                                        IHttpContextAccessor httpContextAccessor)
       {
           this.eventLogService = eventLogService;
           this.httpContextAccessor = httpContextAccessor;
       }       

       public void LogEvent(EventLogData eventLogData)
       {
           // Added custom logic that modifies the logged event data      
           eventLogData.EventDescription += $" Action was performed from {httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString()}";   
           // Call to the previous implementation of the method to do the actual logging
           eventLogService.LogEvent(eventLogData);
       }
   }

   ```

   <!-- dev-model:core end -->
4. Register the service implementation within the application's IoC container via the `RegisterImplementation` attribute.

   ```csharp

   using CMS;

   [assembly: RegisterImplementation(typeof(IEventLogService), typeof(EventLogServiceCustomized))]
   public class EventLogServiceCustomized : IEventLogService

   ```

The system now uses your service implementation in place of the previous one. The service's core behavior remains unchanged, but it also executes the additional logic when used.

## Decorate services via inheritance

Xperience services with public implementations can be decorated via inheritance. This form of customization is only possible for services that

- expose their implementation
- contain virtual members (overridable from derived classes)

### Example

The following example demonstrates decoration via inheritance:

1. Create a new implementation that inherits from the default implementation of the desired service. This example modifies `EventLogService` (the implementation of `IEventLogService`) to add more information to the application's event logging.

   - For best practices about integrating custom code, see [Adding custom assemblies](https://docs.kentico.com/13/custom-development/adding-custom-assemblies.md).

   ```csharp

   using CMS.EventLog;

   public class EventLogServiceCustomized : EventLogService
   {    
   }

   ```
2. Override the virtual members that you wish to decorate. To keep the original behavior, call their base implementation from within the overridden member. Add custom logic as required.

   <!-- dev-model:mvc start -->

   **MVC 5 development model.** Applies only when building with ASP.NET MVC 5. If this page also covers ASP.NET Core, that version is in its own block.

   ```csharp

   using CMS.EventLog;
   using CMS.Helpers;

   public class EventLogServiceCustomized : EventLogService
   {
       public override void LogEvent(EventLogData eventLogData)
       {
           // Added custom logic that modifies the logged event data
           eventLogData.EventDescription += $" Action was performed from {RequestContext.UserHostAddress}";
           // Call to the default implementation of the method to do the actual logging
           base.LogEvent(eventLogData);
       }
   }

   ```

   <!-- dev-model:mvc end -->

   <!-- dev-model:core start -->

   **ASP.NET Core development model.** Applies only when building with ASP.NET Core. If this page also covers MVC 5, that version is in its own block.

   ```csharp

   using CMS.EventLog;

   public class EventLogServiceCustomized : EventLogService
   {
       private readonly IHttpContextAccessor httpContextAccessor;

       public EventLogServiceCustomized(IHttpContextAccessor httpContextAccessor)
       {
           this.httpContextAccessor = httpContextAccessor;
       }

       public override void LogEvent(EventLogData eventLogData)
       {
           // Added custom logic that modifies the logged event data
           eventLogData.EventDescription += $" Action was performed from {httpContextAccessor.HttpContext.Connection.RemoteIpAddress}";
           // Call to the default implementation of the method to do the actual logging
           base.LogEvent(eventLogData);
       }
   }

   ```

   <!-- dev-model:core end -->
3. Register the new implementation using the `RegisterImplementation` assembly attribute.

   ```csharp

   using CMS;

   [assembly: RegisterImplementation(typeof(IEventLogService), typeof(EventLogServiceCutomized))]
   public class EventLogServiceCustomized : EventLogService

   ```

The system now uses your service implementation in place of the default one. The service's core behavior remains unchanged, but it also executes the additional logic when used.
