Showing posts with label xConnect. Show all posts
Showing posts with label xConnect. Show all posts

Wednesday, 1 March 2023

When Disabling xDB Isn't Enough

If you read the documentation on using CMS-only mode to run Sitecore without xDB you'd be forgiven for thinking that a config patch such as this is the simple end of the story:

<configuration>
    <sitecore>
        <settings>
            <setting name="Xdb.Enabled" value="false" />
            <setting name="Xdb.Tracking.Enabled" value="false" />
        </settings>
    </sitecore>
</configuration>

Unfortunately as someone on Slack recently discovered, this doesn't help if you're trying to run Sitecore (XP container images, but in CMS-only mode without the xConnect instances) in containers. 

The issue is fairly obvious when you notice CM is not starting and take a look at an example of the logs

920 08:52:34 ERROR Health check Sitecore.XConnect.Client.WebApi.CollectionWebApiClient completed after 0.0038ms with status Unhealthy and 'Error during CollectionWebApiClient initialization: An error occurred while sending the request.'

1920 08:52:35 ERROR Health check Sitecore.XConnect.Client.WebApi.ConfigurationWebApiClient completed after 0.0054ms with status Unhealthy and 'Error during ConfigurationWebApiClient initialization: An error occurred while sending the request.'

1920 08:52:36 ERROR Health check Sitecore.XConnect.Client.WebApi.SearchWebApiClient completed after 0.0068ms with status Unhealthy and 'Error during SearchWebApiClient initialization: An error occurred while sending the request.'

Yes, there are in fact health checks on CM and CD which check the status of xConnect, and completely ignore the config settings I mentioned above.

Not to worry, there are a couple of options at this point:

  1. Use a config patch to remove the health checks (the easier option)
  2. Update and override the health checks so that they respect the Xdb.Enabled setting

Config patch

Here's an easy patch you can apply which should remove these from your Sitecore configuration and complete the disabling of xDB:

Updating the code

The "proper" way, I feel, would be to update the code to respect the Xdb.Enabled setting. This is what the setting is indicating, and what the documentation explains that it is for.

To take XConnectCollectionHealthCheckServicesConfigurator as an example:

public class XConnectCollectionHealthCheckServicesConfigurator : Sitecore.XConnect.Client.Configuration.HealthCheckServicesConfigurators.XConnectCollectionHealthCheckServicesConfigurator
{
  protected override IHealthCheck CreateCommonWebApiHealthCheck(IServiceProvider provider)
  {
    if (Sitecore.Configuration.Settings.GetBoolSetting("Xdb.Enabled", true))
      return base.CreateCommonWebApiHealthCheck(provider);
    else
      return new SuccessHealthCheck();
  }
}

public class SuccessHealthCheck : IHealthCheck
{
  public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
  {
    return Task.FromResult(HealthCheckResult.Healthy());
  }
}

We add our settings check, and - because there does not seem to be any easy out-of-the-box way to return a successful health check - we also need to create a class for that. Repeat for all 3 health checks, and you're good to go.

Enjoy running your Sitecore topology nice and lean!

Friday, 21 February 2020

xDB Migration Wizard - Complex Facets and Facet Lists

The documentation for mapping custom facets using the xDB migration wizard is quite good for simple facets (ie. 1-1 string field mapping between Mongo and xConnect), however I've come across a few clients now who have needed something a bit more complex - generally in the form of a facet list.

I'm going to assume that you've been through the documentation in the link above and successfully mapped one or more simple facets.

I'm going to run through the scenario of migrating a Contact facet called CustomFacet which has a IElementCollection<CustomObject> called CustomObjects in 8.x Mongo to a Contact facet called CustomFacet which has a Dictionary<string, CustomObject> called CustomObjects in 9.x xConnect. CustomObject has 2 fields:
  • Id: int
  • Start: DateTime
  • Name: string

NOTE: Before you do anything, make sure you've built and deployed your custom model(s).  Verify that the json looks correct, and all your properties are appearing in your json file!
Our json file looks like:
{
  "Name": "My.CustomModel",
  "Version": "1.0",
  "References": [
    {
      "Name": "XConnect",
      "Version": "1.0"
    },
    {
      "Name": "Sitecore.XConnect.Collection.Model",
      "Version": "9.0"
    }
  ],
  "Types": {
    "My.CustomFacet": {
      "Type": "Facet",
      "BaseType": "Sitecore.XConnect.Facet",
      "ClrType": "My.CustomFacet, ModelSerializer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Properties": {
        "CustomObjects": {
          "Type": {
            "String": "My.CustomObject"
          }
        }
      }
    },
    "My.CustomObject": {
      "Type": "Complex",
      "ClrType": "My.CustomObject, ModelSerializer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Properties": {
        "Id": {
          "Type": "Int32"
        },
        "Start": {
          "Type": "DateTime"
        },
        "Name": {
          "Type": "String"
        }
      }
    }
  },
  "Facets": [
    {
      "Target": "Contact",
      "Name": "Custom",
      "Type": "My.CustomFacet"
    }
  ]
}

our json in Mongo looks like:
{
    "_id" : LUUID("a1b928fb-1ba9-824c-8fa7-2b5bc92b36c9"),
    "Identifiers" : {
        "Identifier" : "fb28b9a1-a91b-4c82-8fa7-2b5bc92b36c9"
    },
    "CustomFacet" : {
        "CustomObjects" : {
            "1" : {
                "Id" : 58,
                "Name" : "My First Object",
                "Date" : ISODate("2020-02-20T07:28:36.376Z")
            },
            "2" : {
                "Id" : 57,
                "Name" : "My Second Object",
                "Date" : ISODate("2020-02-18T07:28:36.376Z")
            },
            "3" : {
                "Id" : 102,
                "Name" : "My Third Object",
                "Date" : ISODate("2020-02-17T07:28:36.376Z")
            }
        }
    }
}

I'll be using the Addresses facet as a reference, as this is very similar.  We'll just need to edit one file:

[SupportedIds(new string[] {"{85C3A33B-AAD7-4982-98E5-D67729DDBCA8}"})]
  public class CustomEntriesFromXdbListValueAccessorConverter : BaseItemModelConverter
  {
    public CustomEntriesFromXdbListValueAccessorConverter(IItemModelRepository repository)
      : base(repository)
    {
    }

    protected override ConvertResult ConvertSupportedItem(
      ItemModel source)
    {
      DictionaryEntriesFromDocumentValueReaderConverter valueReaderConverter1 = new DictionaryEntriesFromDocumentValueReaderConverter(this.ItemModelRepository);
      valueReaderConverter1.IgnoreValidation = true;
      valueReaderConverter1.DictionaryFieldName = "CustomObjects";
      DictionaryEntriesFromDocumentValueReaderConverter valueReaderConverter2 = valueReaderConverter1;
      valueReaderConverter2.FieldsWithValuesForTheKeysToExclude = new string[0];
      ValueAccessor valueAccessor = new ValueAccessor();
      ConvertResult convertResult = valueReaderConverter2.Convert(source);
      if (convertResult.WasConverted)
        valueAccessor.ValueReader = convertResult.ConvertedValue;
      return this.PositiveResult((IValueAccessor) valueAccessor);
    }
  }

Specify data to read from MongoDB

Navigate to /sitecore/system/Data Exchange/xDB Data Migration 8x to 9/Data Access/Value Accessor Sets/Providers/MongoDB and create the following items and fields:
  • MongoDB
    • MongoDB Contact
      • CustomFacet on MongoDB Contact
        Field Name:CustomFacet
        Converter Type:Sitecore.DataExchange.Providers.MongoDB.Converters.DataAccess.ValueAccessors.DocumentFieldValueAccessorConverter, Sitecore.DataExchange.Providers.MongoDB
    • MongoDB Contact CustomObject List
      Template:/sitecore/templates/Data Exchange/Providers/MongoDB/Data Access/Value Accessor Sets/MongoDB Document Value Accessor Set
      Converter type:Sitecore.DataExchange.Converters.DataAccess.ValueAccessors.ChildBasedValueAccessorSetConverter, Sitecore.DataExchange
      • CustomObject Entries on MongoDB Contact
        Template:/sitecore/templates/Data Exchange/Tools/xDB Data Migration Tool/Data Access/Value Accessors/MongoDB Non Preferred Entries from xDB List Value Accessor
        Converter Type:My.CustomEntriesFromXdbListValueAccessorConverter, My
    • MongoDB CustomObject Entry
      Template:/sitecore/templates/Data Exchange/Providers/MongoDB/Data Access/Value Accessor Sets/MongoDB Document Value Accessor Set
      Converter type:Sitecore.DataExchange.Converters.DataAccess.ValueAccessors.ChildBasedValueAccessorSetConverter, Sitecore.DataExchange
      • Id
        Template:/sitecore/templates/Data Exchange/Tools/xDB Data Migration Tool/Data Access/Value Accessors/MongoDB Preferred Entry from xDB List Value Accessor
        Converter type:Sitecore.DataExchange.Providers.MongoDB.Converters.DataAccess.ValueAccessors.DocumentFieldValueAccessorConverter, Sitecore.DataExchange.Providers.MongoDB
      • Date
        Template:/sitecore/templates/Data Exchange/Tools/xDB Data Migration Tool/Data Access/Value Accessors/MongoDB Preferred Entry from xDB List Value Accessor
        Converter type:Sitecore.DataExchange.Providers.MongoDB.Converters.DataAccess.ValueAccessors.DocumentFieldValueAccessorConverter, Sitecore.DataExchange.Providers.MongoDB
      • Name
        Template:/sitecore/templates/Data Exchange/Tools/xDB Data Migration Tool/Data Access/Value Accessors/MongoDB Preferred Entry from xDB List Value Accessor
        Converter type:Sitecore.DataExchange.Providers.MongoDB.Converters.DataAccess.ValueAccessors.DocumentFieldValueAccessorConverter, Sitecore.DataExchange.Providers.MongoDB

Specify data to write to xConnect contact facet

Navigate to /sitecore/system/Data Exchange/xDB Data Migration 8x to 9/Data Access/Value Accessor Sets/Providers/xConnect
  • xConnect
    • xConnect Contact
      • CustomFacet on xConnect Contact
        Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessors/xConnect Entity Facet Value Accessor
        Facet Definition:Collection Models/xDB Data Migration Tool/xDB Migratino Collection Model/Facets/Contact/CustomFacet
        Mapping Set:Value Mapping Sets/MongoDB to xConnect Contact Mappings/MongoDB CustomObjects to xConnect Contact CustomFacet
        Converter Type:Sitecore.DataExchange.Providers.XConnect.Converters.DataAccess.EntityFacetValueAccessorConverter, Sitecore.DataExchange.Providers.XConnect
    • xConnect Contact CustomFacet
      Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessor Sets/xConnect Entity Facet Value Accessor Set
      Converter type:Sitecore.DataExchange.Converters.DataAccess.ValueAccessors.ChildBasedValueAccessorSetConverter, Sitecore.DataExchange
      • CustomObjects on CustomFacet on xConnect Contact
        Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessors/xConnect Entity Facet Dictionary Property Value Accessor
        Facet Property:Collection Models/xDB Data Migration Tool/xDB Data Migration Collection Model/Facets/Contact/CustomFacet/CustomObjects
        Mapping set:Value Mapping Sets/MongoDB to xConnect Contact Mappings/MongoDB CustomObjects to xConnect Contact CustomObjects
        Converter Type:Sitecore.DataExchange.Providers.XConnect.Converters.DataAccess.EntityFacetDictionaryPropertyValueAccessorConverter, Sitecore.DataExchange.Providers.XConnect
    • xConnect Contact CustomObject
      Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessor Sets/xConnect XObject Value Accessor Set
      Converter type:Sitecore.DataExchange.Converters.DataAccess.ValueAccessors.ChildBasedValueAccessorSetConverter, Sitecore.DataExchange
      • Id
        Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessors/xConnect XObject Property Value Accessor
        Converter type:Sitecore.DataExchange.Providers.XConnect.Converters.DataAccess.XObjectPropertyValueAccessorConverter, Sitecore.DataExchange.Providers.XConnect
      • Date
        Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessors/xConnect XObject Property Value Accessor
        Converter type:Sitecore.DataExchange.Providers.XConnect.Converters.DataAccess.XObjectPropertyValueAccessorConverter, Sitecore.DataExchange.Providers.XConnect
      • Name
        Template:/sitecore/templates/Data Exchange/Providers/xConnect/Data Access/Value Accessors/xConnect XObject Property Value Accessor
        Converter type:Sitecore.DataExchange.Providers.XConnect.Converters.DataAccess.XObjectPropertyValueAccessorConverter, Sitecore.DataExchange.Providers.XConnect

Configure mapping from MongoDB contact to xConnect contact facet

Navigate to /sitecore/system/Data Exchange/xDB Data Migration 8x to 9/Value Mapping Sets/MongoDB to xConnect Contact Mappings
  • MongoDB to xConnect Contact Mappings
    • MongoDB Contact to Contact Model
      • CustomFacet
        Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping
        Source Accessor:CustomFacet on MongoDB Contact
        Target Accessor:Data Access/Value Accessor Sets/Providers/xConnect/xConnect Contact/CustomFacet on xConnect Contact
        Converter type:Sitecore.DataExchange.Converters.DataAccess.Mappings.MappingConverter, Sitecore.DataExchange
    • MongoDB CustomObjects to xConnect Contact CustomFacet
      Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping Set
      Converter type:Sitecore.DataExchange.Converters.DataAccess.Mappings.ChildBasedMappingSetConverter, Sitecore.DataExchange
      • CustomObjects
        Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping
      • Source accessor:
        CustomObject Entries on MongoDB Contact
        Target aceessor:
        Data Access/Value Accessor Sets/Providers/xConnect/xConnect Contact CustomFacet/CustomObjects on CustomFacet on xConnect Contact

  • MongoDB CustomObject to xConnect Contact CustomObject
    Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping Set
    Converter type:Sitecore.DataExchange.Converters.DataAccess.Mappings.ChildBasedMappingSetConverter, Sitecore.DataExchange
    • Id
      Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping
      Source Accessor:Id on MongoDB Contact CustomObject
      Target Accessor:Data Access/Value Accessor Sets/Providers/xConnect/xConnect Contact CustomObject/Id
      Converter type:Sitecore.DataExchange.Converters.DataAccess.Mappings.MappingConverter, Sitecore.DataExchange
    • Name
      Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping
      Source Accessor:Id on MongoDB Contact CustomObject
      Target Accessor:Data Access/Value Accessor Sets/Providers/xConnect/xConnect Contact CustomObject/Id
      Converter type:Sitecore.DataExchange.Converters.DataAccess.Mappings.MappingConverter, Sitecore.DataExchange
    • Date
      Template:/sitecore/templates/Data Exchange/Framework/Data Access/Mapping/Value Mapping
      Source Accessor:Id on MongoDB Contact CustomObject
      Target Accessor:Data Access/Value Accessor Sets/Providers/xConnect/xConnect Contact CustomObject/Id
      Converter type:Sitecore.DataExchange.Converters.DataAccess.Mappings.MappingConverter, Sitecore.DataExchange