6

We are trying to get list of contacts programmatically in latest Sitecore 9.0.1. We want to show list of contacts on pages based on their linkage to certain list.

We need to get the same list of contacts that we can see in List Manager for either Contact List or Segmented List types.

Our aim is to get contacts for segmented lists in first place. We have created couple of segmented lists that have only one rule and that goal has been triggered for that contact.

Best would be to get list of contacts directly for defined segmented list but getting list of contacts where interaction with precise goal was trigger would do the trick also (as it would copy rule on segmented list).

There is no mentioning of this in documentation as far as I can see and decompiling Sitecore code was not helpful so far neither.

5

Use the following example to get contacts from contact list:

Guid contactListId = Guid.NewGuid(); //Contact list Id
int batchSize = 200;
var expandOptions = 
    new ContactExpandOptions(CollectionModel.FacetKeys.PersonalInformation);
var segmentationEngine = ServiceLocator.ServiceProvider
    .GetService<ISegmentationEngine>();
var listSubscriptionConditions = new ListSubscriptionMatches()
{
    ListId = contactListId
};

var contacts = segmentationEngine
    .FindContacts(listSubscriptionConditions, batchSize, expandOptions);

In order to get contacts from segmented list, first you should get referenced segment definitions and retrieve conditions from them:

var contactListProvider = ServiceLocator.ServiceProvider.GetService<IContactListProvider>();
var contactProvider = ServiceLocator.ServiceProvider.GetService<IContactProvider>();
var contactList = contactListProvider.Get(contactListId, cultureInfo);

var segments = contactList.SegmentDefinitionIds
    .Select(id => segmentManager.Get(id, cultureInfo));
var ruleConditions = segments.SelectMany(x => x.Rules)
    .Select(x => x.Condition);

Then use conditions to build query and get contacts:

int batchSize = 200;
var expandOptions = new ContactExpandOptions(CollectionModel.FacetKeys.PersonalInformation);
var contactSearchExpressionBuilder = ServiceLocator.ServiceProvider
    .GetService<IContactSearchExpressionBuilder>();
var segmentationEngine = ServiceLocator.ServiceProvider
    .GetService<ISegmentationEngine>();

var contactSearchQuery = contactSearchExpressionBuilder.BuildQueryFactories(ruleConditions)
    .CombineUsingOr();
var contacts = segmentationEngine.FindContacts(contactSearchQuery, batchSize, expandOptions);

Update:

You need to add reference to Microsoft.Extensions.DependencyInjection; to not get next error "a non generic method cannot be used with type arguments" in ServiceLocator.ServiceProvider.GetService<IContactSearchExpressionBuilder>();

  • And these are necessary using: using Sitecore.Marketing.Definitions; using Sitecore.Marketing.Definitions.ContactLists; using Sitecore.XConnect; using Sitecore.XConnect.Client; using Sitecore.XConnect.Client.Configuration; using Sitecore.XConnect.Collection.Model; using Sitecore.XConnect.Operations; using Sitecore.XConnect.Segmentation; using Sitecore.Marketing.Definitions.Segments; using Sitecore.XConnect.Segmentation.ExpressionBuilder; using Microsoft.Extensions.DependencyInjection; using Sitecore.XConnect.Segmentation.Predicates; – Peter Procházka Mar 9 '18 at 19:17
  • Working as expected. Thanks for the code Vlad – Peter Procházka Mar 9 '18 at 20:51
  • In your code, how to get instance of contactListManager? – Volodymyr Hil Jun 7 '18 at 20:44
  • @VolodymyrHil I updated my answer – Vlad Iobagiu Jun 8 '18 at 3:34
4

I have combined Vlad's code and put it into dedicated 'ListManager' class and created a method that retrieves contacts from list by its id and it could take both ContactList and SegmentList. You need to registed this class in the IoC in order to resolve dependencies. Here is what I have. This is tested and working on Sitecore 9.0.1:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Sitecore.Data;
using Sitecore.ListManagement;
using Sitecore.ListManagement.XConnect;
using Sitecore.XConnect;
using Sitecore.XConnect.Client.Synchronous;
using Sitecore.XConnect.Collection.Model;
using Sitecore.XConnect.Segmentation;
using Sitecore.XConnect.Segmentation.ExpressionBuilder;
using Sitecore.XConnect.Segmentation.Predicates;
using Sitecore.XConnect.Segmentation.Predicates.Contacts;

public class ListManager
{
    private readonly IContactListProvider contactListProvider;
    private readonly IContactSearchExpressionBuilder expressionBuilder;
    private readonly ISegmentationEngine segmentationEngine;

    public ListManager(
        IContactListProvider contactListProvider,
        IContactSearchExpressionBuilder expressionBuilder,
        ISegmentationEngine segmentationEngine)
    {
        this.contactListProvider = contactListProvider;
        this.expressionBuilder = expressionBuilder;
        this.segmentationEngine = segmentationEngine;
    }

    /// <summary>
    /// Retrieves contacts from list. List can be of both 'ContactList' or 'SegmentedList'
    /// </summary>
    /// <param name="listId">ID of the list (GUID).</param>
    public IEnumerable<Contact> GetContactsFromList(Guid listId)
    {
        var listItem = Sitecore.Context.Database.GetItem(new ID(listId));
        if (listItem != null)
        {
            var listType = listItem["Type"];

            const int batchSize = 200;
            var expandOptions = new ContactExpandOptions(CollectionModel.FacetKeys.PersonalInformation);

            IEntityBatchEnumerator<Contact> contacts = null;

            if (listType.Equals("ContactList", StringComparison.InvariantCultureIgnoreCase))
            {

                var listSubscriptionConditions = new ListSubscriptionMatches()
                {
                    ListId = listId
                };

                contacts = this.segmentationEngine.FindContacts(
                    listSubscriptionConditions, 
                    batchSize, 
                    expandOptions);
            }

            if (listType.Equals("SegmentedList", StringComparison.InvariantCultureIgnoreCase))
            {
                // works only if culture is 'en'
                var culture = CultureInfo.GetCultureInfo("en");
                var contactList = this.contactListProvider.Get(listId, culture);

                var segments = contactList.SegmentDefinitions;
                var ruleConditions = segments.SelectMany(x => x.Rules).Select(x => x.Condition);

                var contactSearchQuery = this.expressionBuilder.BuildQueryFactories(ruleConditions)
                    .CombineUsingOr();

                contacts = this.segmentationEngine.FindContacts(
                    contactSearchQuery, 
                    batchSize, 
                    expandOptions);
            }

            if (contacts != null)
            {
                while (contacts.MoveNext())
                {
                    foreach (var contact in contacts?.Current ?? Enumerable.Empty<Contact>())
                    {
                        yield return contact;
                    }
                }
            }
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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