The best way to understand why something does not work is debugging it. Unfortunately, it is not always possible to attach VS or windbg to a running process. In such cases, I usually extend the code with logging and check the output.


Some time ago I had issues with non-working Marketing Automation condition. This was custom condition and I had code for it. After some time monitoring the MA pool without success, I decided to inject logging into the condition Evaluate method to troubleshoot it. The conditions are processed by maengine service, thus usual Sitecore Log.Info() call won’t work here since there is no Sitecore.Kernel assembly reference. Using DI and passing the ILogger via condition constructor won’t work either since the conditions are created using Activator and require parameter-less constructor.


MA has quite elegant extension points, which allow us to get the ILogger from condition. The Evaluate method gets IRuleExecutionContext as a parameter, the interface has only one method Fact which is used for getting contact, interaction and other required information. We will use it to get the needed ILogger implementation. I will use test FirstNameCondition further to demonstrate the behavior.


using Serilog;
using Sitecore.Framework.Rules;
using Sitecore.XConnect;
using Sitecore.XConnect.Collection.Model;

namespace TestCondition
{
public class FirstNameCondition : ICondition
{
public bool Evaluate(IRuleExecutionContext context)
{
var logger = context.Fact<ILogger>();
logger.Information("Condition was executed");
var contact = context.Fact<Contact>();
return contact.Personal()?.FirstName == "Sergey";
}
}
}

By default, the ILogger object is not present in context and we need to register it. It can be done by overriding the PopulateScopedFacts method of the ConditionEvaluationService.

public class ConditionEvaluationService : Sitecore.Xdb.MarketingAutomation.Rules.ConditionEvaluationService
{
private readonly ILogger<Sitecore.Xdb.MarketingAutomation.Rules.ConditionEvaluationService> _logger;

public ConditionEvaluationService(
ILogger<Sitecore.Xdb.MarketingAutomation.Rules.ConditionEvaluationService> logger,
IConditionSerializer serializer, IServiceProvider serviceProvider) : base(logger, serializer,
serviceProvider)
{
_logger = logger;
}

public ConditionEvaluationService(
ILogger<Sitecore.Xdb.MarketingAutomation.Rules.ConditionEvaluationService> logger,
IConditionSerializer serializer, IConditionCache cache, IServiceProvider serviceProvider) : base(logger,
serializer, cache, serviceProvider)
{
_logger = logger;
}

protected override void PopulateScopedFacts(FactSpecificier facts, IContactProcessingContext processingContext,
IConditionServices conditionServices, ISegmentationServiceContext segmentationServiceContext)
{
base.PopulateScopedFacts(facts, processingContext, conditionServices, segmentationServiceContext);
facts.Fact<ILogger>(_logger);
}
}

The corresponding service must be replaced by a custom one in the following file:

App_data\jobs\continuous\AutomationEngine\App_Data\Config\sitecore\MarketingAutomation\sc.MarketingAutomation.ConditionEvaluationService.xml
<MarketingAutomation.Rules.ConditionEvaluationService>
<Type>CustomNamespace.ConditionEvaluationService, CustomAssembly</Type>
<As>Sitecore.Xdb.MarketingAutomation.Core.Rules.IConditionEvaluationService, Sitecore.Xdb.MarketingAutomation.Core</As>
<LifeTime>Singleton</LifeTime>
</MarketingAutomation.Rules.ConditionEvaluationService>