1

I am trying to update & query an xDB contact via the XConnect Client API from a console application.

I can query and retrieve the default facets e.g. PersonalInformation.FirstName PersonalInformation.LastName as expected.

I have created a custom facet following the tutorial 5 on the sitecore docs.

However when I try and retrieve my custom facet, it is throwing an exception: contact.GetFacet<SportType>(SportType.DefaultKey); enter image description here

When I look at the contacts facets, all the custom models are binding to UntypedFacet: enter image description here

When I retrieve and update these Facets on my Sitecore instance, it works successfully. It just wont work via the Client API.

My environment is running on the Sitecore HabitatHome 9.3 local environment.

Console API Code

var reference = new ContactReference(Guid.Parse("b483f033-8875-0000-0000-05c029e74ad5"));

var contact = client.Get<Contact>(reference, new ContactExpandOptions(SportName.DefaultKey,SportType.DefaultKey,
        CustomFacetInformation.DefaultFacetKey, PersonalInformation.DefaultFacetKey) { });

var customFacet = contact.GetFacet<CustomFacetInformation>(CustomFacetInformation.DefaultFacetKey);
if(customFacet == null)
{
    var customFacetInformation = new CustomFacetInformation()
    {
        CarModel = "Mazda",
        PassportNumber = "XYZ123",
        PreferredLanguage = "English"
    };
    client.SetFacet(contact, CustomFacetInformation.DefaultFacetKey, customFacetInformation);
}
var sportType = contact.GetFacet<SportType>(SportType.DefaultKey);

Custom Facet Classes:

namespace Sitecore.HabitatHome.Global.Website.Facets
{
[FacetKey(DefaultFacetKey)]
    [Serializable]
    public class CustomFacetInformation : Facet
    {
        public const string DefaultFacetKey = "CustomFacetInformation";
        public CustomFacetInformation() { }
        public string CarModel { get; set; }
        public string PassportNumber { get; set; }
        public string PreferredLanguage { get; set; }
    }

    public class CustomFacetCollectionModel
    {
        public static XdbModel Model { get; } = CustomFacetCollectionModel.BuilddCustomModel();
        private static XdbModel BuilddCustomModel()
        {
            XdbModelBuilder xdbModelBuilder = new XdbModelBuilder("CustomFacetCollectionModel", new XdbModelVersion(1, 0));
            xdbModelBuilder.ReferenceModel(CollectionModel.Model);
            xdbModelBuilder.DefineFacet<Contact, CustomFacetInformation>(CustomFacetInformation.DefaultFacetKey);
            return xdbModelBuilder.BuildModel();
        }
    }
}

Sitecore Config:

<xconnect>
    <runtime type="Sitecore.XConnect.Client.Configuration.RuntimeModelConfiguration,Sitecore.XConnect.Client.Configuration">
        <schemas hint="list:AddModelConfiguration">
            <schema name="customFacetCollectionModel" type="Sitecore.XConnect.Client.Configuration.StaticModelConfiguration,Sitecore.XConnect.Client.Configuration" patch:after="schema[@name='collectionmodel']">
                <param desc="modeltype">Sitecore.HabitatHome.Global.Website.Facets.CustomFacetCollectionModel, Sitecore.HabitatHome.Global.Website</param>
            </schema>
        </schemas>
    </runtime>
</xconnect>

Facet Model: CustomFacetCollectionModel, 1.0.json

{
  "Name": "CustomFacetCollectionModel",
  "Version": "1.0",
  "References": [
    {
      "Name": "XConnect",
      "Version": "1.0"
    },
    {
      "Name": "Sitecore.XConnect.Collection.Model",
      "Version": "9.3"
    }
  ],
  "Types": {
    "Sitecore.HabitatHome.Global.Website.Facets.CustomFacetInformation": {
      "Type": "Facet",
      "BaseType": "Sitecore.XConnect.Facet",
      "ClrType": "Sitecore.HabitatHome.Global.Website.Facets.CustomFacetInformation, Sitecore.HabitatHome.Global.Website, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Properties": {
        "CarModel": {
          "Type": "String"
        },
        "PassportNumber": {
          "Type": "String"
        },
        "PreferredLanguage": {
          "Type": "String"
        }
      }
    }
  },
  "Facets": [
    {
      "Target": "Contact",
      "Name": "CustomFacetInformation",
      "Type": "Sitecore.HabitatHome.Global.Website.Facets.CustomFacetInformation"
    }
  ]
}

1 Answer 1

2

Well, you spend 6 hours investigating. Post the question and 30 minutes later figure it out.

The culprit was in the call to the xDBRuntimeModel. I was NOT passing in the custom models. Previous code was:

    var cfg = new XConnectClientConfiguration(
                new XdbRuntimeModel(CollectionModel.Model),
                collectionClient, searchClient, configurationClient);

Working code is:

    var cfg = new XConnectClientConfiguration(
                new XdbRuntimeModel(CollectionModel.Model, CustomFacetCollectionModel.Model, Demo.Foundation.Accounts.Models.AccountCollectionModel.Instance),
                collectionClient, searchClient, configurationClient);

Now the setup code looks like:

// Optional timeout modifier
            var certificateModifier = new CertificateHttpClientHandlerModifier(options);

            List<IHttpClientModifier> clientModifiers = new List<IHttpClientModifier>();
            var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));
            clientModifiers.Add(timeoutClientModifier);

            // This overload takes three client end points - collection, search, and configuration
            var collectionClient = new CollectionWebApiClient(new Uri("https://xyz.dev.local/odata"), clientModifiers, new[] { certificateModifier });
            var searchClient = new SearchWebApiClient(new Uri("https://xyz.dev.local/odata"), clientModifiers, new[] { certificateModifier });
            var configurationClient = new ConfigurationWebApiClient(new Uri("https://xyz.dev.local/configuration"), clientModifiers, new[] { certificateModifier });

            var cfg = new XConnectClientConfiguration(
                new XdbRuntimeModel(CollectionModel.Model, CustomFacetCollectionModel.Model, Demo.Foundation.Accounts.Models.AccountCollectionModel.Instance),
                collectionClient, searchClient, configurationClient);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.