Question:

How to properly configure a custom facet in Sitecore 9.1

Kayden: 19 May 2022

I have been trying the Sitecore samples to define a custom facet, and it all works if I do it outside from Sitecore. But when I want Sitecore to track the contacts and add data to the custom facet, I get the following error:

18452 23:26:42 ERROR Cannot create tracker.
Exception: System.ArgumentException
Message: The specified type is not a valid facet type.
Parameter name: facetType
Source: Sitecore.Analytics.Model
    at Sitecore.Analytics.Model.Framework.ModelFactory.CreateFacet(Type facetType)
    at Sitecore.Analytics.Model.Framework.Faceted.AddFacet(String name, Type type)

I have set up the facet as:

[Serializable]
[FacetKey(DefaultFacetKey)]
public class MemberProfile : Facet
{
    public const string DefaultFacetKey = "MemberProfile";

    public MemberProfile()
    {        }

    public int Zone
    {
        get;
        set;
    }
//OTHER PROPERTIES HERE
}

This is my model:

public class MemberModel
{
    public static XdbModel Model { get; } = BuildModel();

    private static XdbModel BuildModel()
    {
        XdbModelBuilder modelBuilder =
            new XdbModelBuilder("MemberModel", new XdbModelVersion(1, 0));

        // Facets and events here
        modelBuilder.ReferenceModel(Sitecore.XConnect.Collection.Model.CollectionModel.Model);

        modelBuilder.DefineFacet<Contact, MemberProfile>(MemberProfile.DefaultFacetKey);

        return modelBuilder.BuildModel();
    }
}

and I have serialized it and placed the .json file in xConnect/Data.

{
  "Name": "MemberModel",
  "Version": "1.0",
  "References": [
    {
      "Name": "XConnect",
      "Version": "1.0"
    },
    {
      "Name": "Sitecore.XConnect.Collection.Model",
      "Version": "9.0"
    }
  ],
  "Types": {
    "MemberProfile": {
      "Type": "Facet",
      "BaseType": "Sitecore.XConnect.Facet",
      "ClrType": "XXX.MemberProfile, ModelSerializer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Properties": {
        "Zone": {
          "Type": "Int32"
        },
      }
    }
  },
  "Facets": [
    {
      "Target": "Contact",
      "Name": "MemberProfile",
      "Type": "MemberProfile"
    }
  ]
}

Finally, in the Sitecore.XConnect.Client.config I have added:

  <schema name="membermodel" type="Sitecore.XConnect.Client.Configuration.StaticModelConfiguration,Sitecore.XConnect.Client.Configuration">
      <param desc="modeltype">XXX.MemberModel, SEA.Models</param>
  </schema>

I have decompiled the Sitecore.Analytics.Model assembly to look at what is it doing when Framework.ModelFactory.CreateFacet() is called, and it basically tests if my custom facet, which inherits Sitecore.XConnect.Facet, is assignable from Sitecore.Analytics.Model.Framework.IFacet:

if (!typeof (IFacet).IsAssignableFrom(facetType))
    throw new ArgumentException("The specified type is not a valid facet type.", nameof (facetType));

I am obviously doing something wrong or missing something in a config file. I just can't find a solution. Any suggestion is appreciated.

EDIT

Just wanted to share some details here after this worked. The answer I accepted below helped me figure out how to patch the config, also that I needed to copy the json file to more than one folder. There is also another folder to copy the file into: /xconnect/jobs. At last I was able to store the data into the xdb_collection database:

XConnect Data

But I had the issue of not seeing the custom facet in-session, the data was only set to the database and read from there. So, to make it available in-session, I had to add the faced key to the Sitecore.Analytics.Tracking.config file:

<add name="xconnect" type="Sitecore.Analytics.XConnect.DataAccess.XConnectDataAdapterProvider, Sitecore.Analytics.XConnect">
  <facets hint="raw:AddFacet">
    <facet facetKey="Classification"/>
    <facet facetKey="MemberProfile"/>
  </facets>
  <GetOperationTimeout>0.00:00:05</GetOperationTimeout>
</add>

Answer:
Anthony: 19 May 2022

You need to perform the below steps to achieve this:

  1. Create a Custom Facet Model
  2. Register the Custom Facet Model
  3. Deploy Custom Facet model to XDB
  4. Add it to the Sitecore.XConnect.Client.Configuration

In step 3, you need to place .JSON file at two places (You have placed it only one place):

x-connect root path > App_data/Models
x-connect root path > App_data/jobs/continuous/IndexWorker/App_data/Models

In Step 4, update your schema in Sitecore.XConnect.Client.config as below:

<schema name="membermodel" type="Sitecore.XConnect.Client.Configuration.StaticModelConfiguration,Sitecore.XConnect.Client.Configuration" patch:after="schema[@name='collectionmodel']">
  <param desc="modeltype">XXX.MemberModel, SEA.Models</param>

You are missing patch:after="schema[@name='collectionmodel']

Please refer below both the blogs and verify if you missed anything.

Create Custom Facet Model in Sitecore 9 (https://himmatsinghdulawat.blogspot.com/2019/06/create-custom-facet-model-in-sitecore-9.html)

Work with Custom Facet in Sitecore 9 (https://himmatsinghdulawat.blogspot.com/2019/06/work-with-custom-facet-in-sitecore-9.html)

Let me know in case you need further help.