Problem Personalizing with Salesforce Marketing Campaigns in Sitecore
I recently came across an issue synchronizing Salesforce Marketing Campaigns with Sitecore using Sitecore 8.2 and Sitecore Salesforce Connect 1.4.1. While troubleshooting the issue, I discovered a bug in one of the Sitecore Salesforce Connect DLLs. If you discover a similar problem and want to see how it was resolved, please read on.
The CampaignConditionForPersonalization class inherits BaseMembershipCondition<T> from Sitecore.Connect.Crm.Local that takes field name in the constructor and uses it in GetEntityId method to get the campaign ID from the campaign Sitecore item and passes that value to the DoesMatch method.
public abstract class BaseMembershipCondition<T> : OperatorCondition<T> where T : RuleContext
CampaignConditionForPersonalization class in DoesMatch method checks if current contact belongs to campaign. The problem is that the field name passed to the base constructor is "Campaigns".
Sitecore Contact Not Part of Salesforce Marketing Campaign
Background
I recently worked on a project that was implementing personalized content from Sitecore in a Xamarin based mobile application. In this scenario, we wanted to create a unique experience for visitors that were part of a Salesforce campaign using the Sitecore xDB personalization engine. We eventually got to a point when we could see that the Salesforce Campaigns were synchronizing properly, but the personalization rules based on campaign membership were not functioning.Investigation
The adventure began like many complex Sitecore problems by decompiling a DLL. Specifically, the Salesforce DLL, Sitecore.Analytics.Salesforce.dll, was decompiled to discover that the code uses a field with name "Campaigns" on the campaign item to get the ID of the campaign. No field with that name exists on the Sitecore campaign item. The actual field name is "Marketing List ID".The CampaignConditionForPersonalization class inherits BaseMembershipCondition<T> from Sitecore.Connect.Crm.Local that takes field name in the constructor and uses it in GetEntityId method to get the campaign ID from the campaign Sitecore item and passes that value to the DoesMatch method.
public abstract class BaseMembershipCondition<T> : OperatorCondition<T> where T : RuleContext
{
protected BaseMembershipCondition(string fieldName)
{
this.OperatorId = "{10537C58-1684-4CAB-B4C0- 40C10907CE31}";
this.FieldName = fieldName;
}
public string ContactFacetName { get; set; }
public string ExternalEntityId { get; set; }
public string FieldName { get; private set; }
private string GetEntityId(string externalEntityItemId)
{
ID result = ID.Null;
if (ID.TryParse( externalEntityItemId, out result))
{
Database database = Database.GetDatabase( AnalyticsSettings. DefaultDefinitionDatabase);
if (database != null)
{
Item obj = database.GetItem(result);
if (obj != null)
return obj[this.FieldName];
}
}
return (string) null;
}
protected override bool Execute(T ruleContext)
{
if ((object) ruleContext == null)
throw new ArgumentNullException(nameof (ruleContext));
ITracker current = Tracker.Current;
if (current == null)
throw new InvalidOperationException(" Sitecore.Analytics.Tracker. Current is null.");
Contact contact = current.Contact;
if (contact == null)
throw new InvalidOperationException(" Sitecore.Analytics.Tracker. Current.Contact is null.");
return this.DoesMatch(this. GetEntityId(this. ExternalEntityId), contact);
}
protected abstract bool DoesMatch(string entityId, Contact contact);
}
public class CampaignConditionForPersonaliz ation<T> : BaseMembershipCondition<T> where T : RuleContext
{
public CampaignConditionForPersonaliz ation()
: base("Campaigns")
{
this.ContactFacetName = "Salesforce";
}
protected override bool DoesMatch(string entityId, Contact contact)
{
ISalesforceContactData facet = contact.GetFacet< ISalesforceContactData>(this. ContactFacetName);
if (facet == null)
return false;
return facet.Campaigns.Contains( entityId);
}
}
Comments
Post a Comment