Customize system providers

Providers in the Xperience API are classes that allow the system to manipulate objects and perform various actions. The following list presents the providers that the system uses and their purpose:

  • Info providers contain methods for working with specific types of objects stored in the database, such as users, contacts, and custom entities.

    Xperience uses two distinct types of info provider classes.

    Dedicated providers
    This type of provider consists of a dedicated class and interface implementation and is solely responsible for a single database entity – UserInfoProvider (with the IUserInfoProvider interface) responsible for UserInfo objects (from the CMS_User database table), for example. These providers are being actively phased out, to be replaced by generic providers.

    Generic providers
    Generic providers are instances of IInfoProvider<TInfo>, where TInfo is the managed *Info class. We recommend using the generic provider pattern for all custom object types added to the system.

    The info provider customization pattern differs depending on provider type. See Providers based on I*InfoProvider interfaces for dedicated providers and Providers based on IInfoProvider<TInfo> for generic providers. For general overview of both types of providers, see Database table API.

  • Data provider handles low-level database operations. Info providers are built on top of the Data provider and use it to store and fetch data.

  • File system providers allow you to access various file systems. They extend the CMS.IO namespace.

By developing custom providers and using them instead of the standard ones, you can modify the behavior of the application (or a specific feature) according to your requirements.

Customization best practices

When developing custom functionality, we recommend placing your code files into a separate Class Library project (assembly), which is referenced by the main application. See Integrate custom code for details.

Info provider customization

Providers based on IInfoProvider<TInfo>

Generic providers must be customized via inheritance from InfoProviderDecorator<TInfo>. The class offers a set of virtual methods open to modification.

C#
Generic provider customization example

using CMS.DataEngine;

// Decorates a generic provider for objects of the 'MyInfo' type
public class MyInfoProviderDecorator : InfoProviderDecorator<MyInfo>
{
    public MyInfoProviderDecorator(IInfoProvider<MyInfo> decoratedProvider)
        : base(decoratedProvider)
    {
    }

    public override void Set(MyInfo info)
    {
        // Execute custom logic then set using the underlying implementation

        base.Set(info);
    }

    public override void Delete(MyInfo info)
    {
        // Execute custom logic then delete using the underlying implementation

        base.Delete(info);
    }
}

With the custom logic in place, register the decorator class using the RegisterCustomProvider assembly attribute to replace it as the default for objects of the specified Info class.

C#
Register generic provider decorators

[assembly: RegisterCustomProvider(typeof(MyInfoProviderDecorator))]

namespace Sample
{
    public class MyInfoProviderDecorator : InfoProviderDecorator<MyInfo>
    {
        // ...
    }
}

Providers based on I*InfoProvider interfaces

While using providers based on IInfoProvider<TInfo> is strongly recommended for all custom providers, not all system providers currently support this customization pattern. Use the approach described in this section to customize such providers.

Write the custom code

Custom provider classes must inherit from the original implementation. See Decorate system services for more information.

Register custom providers

Registering the customized provider replaces its default system implementation. To register custom providers, use the RegisterCustomProvider assembly attribute.

C#
Custom provider registration

[assembly: RegisterCustomProvider(typeof(UserInfoProviderDecorator))]
namespace Sample
{
    public class UserInfoProviderDecorator : UserInfoProvider
    {
        // Decoration logic...
    }
}

After the custom provider is registered, its implementation is automatically used when resolving the corresponding provider interface (IUserInfoProvider in the case of the example) via dependency injection.

Info object validation

When saving info objects to the database, the system validates object code name format and uniqueness. You can extend this validation by implementing info-specific rules via IInfoValidator<TInfo>.

  1. Create a new class that implements IInfoValidator<TInfo>. Substitute TInfo for the info object you want to validate.
  2. Implement the Validate method. The method must return InfoValidationResult. We recommend storing error resource strings in resource files.
  3. Register the validator into the service container as a singleton using the RegisterImplementation assembly attribute.
C#
Example - Custom validation

using CMS;
using CMS.Core;
using CMS.DataEngine;

// Registers the validator implementation to the service container
[assembly: RegisterImplementation(typeof(IInfoValidator<MyInfo>), typeof(MyInfoValidator), Lifestyle = Lifestyle.Singleton)]

public class MyInfoValidator : IInfoValidator<MyInfo>
{
    public InfoValidationResult Validate(MyInfo info)
    {
        // Perform domain-specific validation and return a corresponding error
        if (!IsValid(info))
        {
            return new InfoValidationResult(nameof(MyInfo.MyField), "resource.key");
        };

        // Indicates successful validation
        return InfoValidationResult.Success;
    }

    private bool IsValid(MyInfo info)
    {
        // Validation logic...
    }
}

Other provider types

Data and file system providers must customize the default implementation by inheriting from the original implementation. See Decorate system services for more information.

To replace the default system implementation, you must register the customized provider classes using the RegisterCustomProvider assembly attribute. See Register custom providers for details about the registration attribute.

Additional customization options

In addition to providers, you can also customize the following helper classes:

Helper class name

Namespace

Description

DirectoryHelper

CMS.IO

Manages directories in the file system.

You can also use global event handlers to customize the behavior of the system. Handlers allow you to execute custom code whenever a specific event occurs in the system, such as page or object changes.