HomeGuidesAPI Reference
Submit Documentation FeedbackJoin Developer CommunityOptimizely GitHubOptimizely NuGetLog In

Customizing conversion from IContent to ContentApiModel

This topic describes how to customize conversion from IContent to ContentApiModel.

This topic describes how to customize conversion from IContent to ContentApiModel. The following phases simplify the process.

  • Convert from IContent to ContentApiModel.
  • Filter data before and after the conversion. See how to customize data returned to clients.
  • Serialize ContentApiModel and returns data to clients.

This topic describes how you customize the conversion from IContent to ContentApiModel. The conversion is responsible for converting PropertyData to PropertyModel. The following image shows the flow.

896896

Several important interfaces and classes appear in the flow image.

  • IContentConverterProvider resolves the correct IContentConverter responsible for converting IContent to ContentApiModel. The default implementation of IContentConvert is DefaultContentConverter.
  • IPropertyConverterProvider resolves the correct IPropertyConverter that takes responsibility to convert a PropertyData to a PropertyModel.

🚧

Caution

Developers can use the classes mentioned above, but only if you really need to because of being an internal namespace or marked as preview.

Several scenarios regarding conversion that developers may face are as follows:

  1. Developers would replace a default property model for a property data by their own model
  2. Developers create a new property data type and need to associate it with a new property model
  3. Developers need to customize our conversion logic

(1) and (2) are much safer than (3) and the following examples show how to handle those scenarios.

🚧

Caution

(3) is complicated and risky so do this only in urgent cases. It is not recommended. Developers can create a new implementation of IContentConverterProvider with a SortOrder higher than 100 and then, implement a new IContentConverter to handle conversion.

Given that a site requires a DateTime in Utc format, and you decide to create a new property data type - CustomPropertyDate to handle this, do the following steps:

  • Create a CustomPropertyDateTime
[Serializable]
[PropertyDefinitionTypePlugIn]
public class CustomPropertyDateTime : PropertyDate
{
    // Empty constructor should be present, otherwise it will cause exception during startup.
    public CustomPropertyDateTime()
    {
      // we should use Field, but for demonstration purpose, we use Date property
      Date = DateTime.MinValue;
    }

    public CustomPropertyDateTime(DateTime dateTime)
    {
      Date = dateTime.ToUniversalTime();
    }

    public override object Value
    {
      get => Date;
      set
      {
        switch (value)
        {
          case string s:
            Date = DateTime.Parse(s, CultureInfo.CurrentCulture).ToUniversalTime();
            Modified();
            return;
          case DateTime d:
            Date = d.ToUniversalTime();
            Modified();
            return;
            default:
            throw new NotSupportedException("Cannot parse date time format.");
        }
      }
    }

    public override PropertyDataType Type => PropertyDataType.Date;
    public override Type PropertyValueType => typeof(DateTime);
}
  • Create a CustomDateTimePropertyModel
public class CustomDateTimePropertyModel : PropertyModel<DateTime?, CustomPropertyDateTime>
  {
    public CustomDateTimePropertyModel(CustomPropertyDateTime utcDateTime) : base(utcDateTime)
    {
      Value = (DateTime)utcDateTime.Value;
    }
  }
  • Create a CustomPropertyConverter
public class CustomPropertyConverter : IPropertyConverter
{
  public IPropertyModel Convert(PropertyData propertyData, ConverterContext contentMappingContext)
  {
    return new CustomDateTimePropertyModel(new CustomPropertyDateTime((propertyData as PropertyDate).Date.Value));
  }
}
  • Create CustomPropertyConverterProvider
public class CustomPropertyConverterProvider : IPropertyConverterProvider
{
  public int SortOrder => 200;

  public IPropertyConverter Resolve(PropertyData propertyData)
  {
    if (propertyData is PropertyDate || propertyData is CustomPropertyDateTime)
    {
      return new CustomPropertyConverter();
    }

    return null;
  }
}
  • Register at Startup in ConfigureServices
services.AddSingleton<IPropertyConverterProvider, CustomPropertyConverterProvider>();
services.AddSingleton<IPropertyConverter, CustomPropertyConverter>();

πŸ“˜

Note

A provider pattern is applied so that if you set SortOrder of another provider higher than Optimizely's, it would be used first. But if another provider doed not handle the case (that is, return null as result), then Optimizely providers are used.