More On Dovetail Carrier RuleSets
I wanted to discuss RuleSets in more detail this time diving deeper into a couple of topics I pulled out of Creating Your First Carrier Extension because they were too advanced for an introduction.
RuleSets Have Context
Your conditions and actions need a way to inspect the message they are evaluating. This is accomplished via the RuleContext object with is give to each condition and action being invoked by the RuleSet. Everytime Carrier starts executing your RuleSet it creates a new RuleSetContext object and puts the message being processed into the context.
Here is the rule context interface.
public interface IRuleContextMESSAGE { MESSAGE Message { get; set; } T FindT() where T : class; bool HasT() where T : class; T PushT(T entity) where T : class; }
It is also useful to have a way to communicate state between conditions and actions. This is what the other methods are for. They allow some things to Push objects into the rule context and others to Find or test to see if the context Has that state present.
Example
In Email Agent there is a condition which detects if the email is regarding a support case.
public class EmailHasCaseId : ICondition<IncomingEmailMessage> { private readonly IDovetailSDKToolkitAdapter _dovetailSdkToolkitAdapter; private readonly EmailAgentSettings _emailAgentSettings; public EmailHasCaseId(IDovetailSDKToolkitAdapter dovetailSdkToolkitAdapter,
EmailAgentSettings emailAgentSettings) { _dovetailSdkToolkitAdapter = dovetailSdkToolkitAdapter; _emailAgentSettings = emailAgentSettings; } public bool IsSatisfied(IRuleContext<IncomingEmailMessage> context) { var caseNoteFormat = _emailAgentSettings.CaseIdentifierFormat; var match = Regex.Match(context.Message.Body + context.Message.Subject,
caseNoteFormat); if(!match.Success) return false; var @case = _dovetailSdkToolkitAdapter.GetCase(match.Groups["caseId"].Value); if(@case == null) return false; context.Push(@case); return true; } }
This condition looks for the case identifier in the email message body and subject. When a case Id is found a class describing the case is pushed into the rule context. Later on other rule actors don’t have to touch the database to look up details about the case they find details about the case in the rule context.
RuleSet Organization
Try to keep your RuleSets focused. They should really only have one reason to exist. What is this RuleSet trying to accomplish. Anytime you feel that you wish Carrier had a branching If statement it likely means you need to create a new RuleSet solving that particular problem.
Here is a common organization of rules in a RuleSet:
- First few rules should answer the question. “Should this ruleset process this Message?”
- Process the Message
- Clean Up
For example Email Agent is broken up into three RuleSets. One for creating cases, another for Logging notes to cases, and another for logging notes to subcases. Here is the RuleSet in charge of logging notes to a case.
The first two rules verify that this rule cares about this message.
The next three rules are the meat they get the job done.
The last rule cleans up.