SkillAgentSearch skills...

Common.DMN.Engine

DMN Engine is a decision engine (rule engine) allowing to execute and evaluate the decisions defined in a DMN model. Its primary target is to evaluate the decision tables that transform the inputs into the output(s) using the decision rules.

Install / Use

/learn @adamecr/Common.DMN.Engine

README

DMN Engine

DMN Engine is a rule engine allowing to execute and evaluate the decisions defined in a DMN model. Its primary target is to evaluate the decision tables that transform the inputs into the output(s) using the decision rules. Simple expression decisions are also supported as well as the complex decision models containing set of dependent decisions (tables or expressions).

The DMN Model is defined using the adopted standard XML file defined by OMG. Such definition can be designed for example using the Camunda modeler, keeping in mind the following principles how the file is parsed and the definition used in DMN Engine.

NuGet package ID: net.adamec.lib.common.dmn.engine

See the latest changes in changelog

Quick start

The basic use case is:

  1. Parse the DMN model from file.
  2. Create an engine execution context and load (and validate) the model into engine context.
  3. Provide the input parameter(s).
  4. Execute (and evaluate) the decision and get the result(s).
var def = DmnParser.Parse(fileName);
var ctx = DmnExecutionContextFactory.CreateExecutionContext(def);
ctx.WithInputParameter("input name", inputValue);
var result = ctx.ExecuteDecision("decision name");

DMN Engine usage flows are quite straightforward.

DMN engine blocks

The decision model can be defined in DMN XML defined by OMG (version 1.1 or 1.3). The XML is parsed into DmnModel using DmnParser.Parse, DmnParser.Parse13, DmnParser.Parse13ext, DmnParser.ParseString, DmnParser.ParseString13 or DmnParser.ParseString13ext methods.

Note: When parsing with version 1.3ext (DmnVersion.DmnVersionEnum.V1_3ext), it still uses the DMN XML 1.3 but with a bit different logic of mapping the XML attributes to definition (details provided later in the document).

The DMN Model is to be further transferred to DmnDefinition using DmnDefinitionFactory.CreateDmnDefinition. The alternative way of creating the DMN Definition is to use the DmnDefinitionBuilder. The builder provides fluent methods to prepare the definition and built it at the end using DmnDefinitionBuilder.Build method.

Once the DMN Definition is ready, it's to be provided to DmnExecutionContextFactory.CreateExecutionContext method to create the DMN execution context. (the DmnExecutionContext can be also created directly from DmnModel using the DmnExecutionContextFactory.CreateExecutionContext overload).

Provide the execution context with input parameters using WithInputParameter or WithInputParameters methods of context and call DmnContext.ExecuteDecision method to get the DmnDecisionResult.

Note: The DMN definition is designed to be "virtually immutable" once created allowing the execution context (execution engine) to reference the definition and its parts without a need to take into a consideration the potential changes in the definition. The meaning of "virtually immutable" is that for sake of simplicity, sometimes the immutability is achieved just by using the read only interface (for example IReadOnlyDictionary hiding some of the methods of Dictionary or IDmnVariable hiding the methods of DmnVariableDefinition).

Build

The library uses the customized MS Build process in projects build and build.tasks. It's safe to remove such projects from solution if needed. Details about the build process are described in build documentation.

Tests

Tests are implemented using MS Test Framework and provide also bunch of sample models that can help together with the test code to better understand how the DMN Engine works and is to be used.

Note: adjust the LogHome variable in nlog.config of test project as you need.

The test code is in shared code project that is "linked" to test projects targeting different platforms (.net core 3.1, 5, 6; .net framework 4.6.2, 4.7.2). DmnTestBase class provides abstraction allowing to simply apply the same tests using the different sources (DMN XML 1.1/1.3/1.3ext or builders).

The "primary" test class inherits from DmnTestBase and contains the test code and is set to test against DMN XML 1.1.

The test classes for DMN 1.3 inherits from "primary" test class and override the Source property to use the DMN 1.3, the tests themselves are just inherited, so no need to code them again. Same approach is used for tests with parser version 1.3ext.

The builder based definition tests are prepared similar way - inherit from "primary" test class and set the Source to used the builders. DmnBuilderSamples class is generated from DMN XML files to provide the same decision model (DMN definition) but using the builders (Note: it might be useful to check this class to have a quick look how the builders work).

Note: I use the test cases also to demonstrate some edge-case or less intuitive behavior, so they can be used also as a study material (tried to explain it in comments in test if needed).

Code Documentation

The code documentation is generated during the customized build using MarkupDoc.

DMN Decision Model

The DMN Model is actually set of inputs (parameters) and decisions.

DMN diagram

The DMN Model XML is parsed (deserialized) using the DmnParser.Parse method getting the fileName as input parameter and returning the DmnModel (deserialized XML) based on such decisions model XML definition. The DmnParser contains a very simple logic only, as its intention is just to deserialize the XML.

model = DmnParser.Parse(fileName);

The XML model definition can also be provided as a string to DmnParser.ParseString method

model = DmnParser.ParseString("xml string");

DmnParser uses the DMN XML v 1.1 by default. It can be overridden using the optional parameter dmnVersion when calling the parser. It can contain value V1_1(default, supporting DMN XML version 1.3), V1_3 or 'V1_3ext(to support DMN XML version 1.3). The values are defined in DmnVersionEnum. Alternative way of using the DMN version 1.3 is to call methods DmnParser.Parse13(fileName), DmnParser.ParseString13("xml string"), DmnParser.Parse13ext(fileName) or DmnParser.ParseString13ext("xml string").

The DmnModel needs to be transformed to the DmnDefinition using the DmnDefinitionFactory that gets the DMN Model and executes "second level parsing" to prepare the DMN Model for the Engine. The most of the "parsing" and validation logic is here. DmnDefinition is then used to create the DmnExecutionContext allowing the execution/evaluation of the decisions based on the parameters provided.

var model=DmnParser.Parse(file);
var definition= DmnDefinitionFactory.CreateDmnDefinition(model);
var ctx = DmnExecutionContextFactory.CreateExecutionContext(definition);

Since DMN Engine v1.1.0, the version provided to parser defines not only the version of DMN XML, but has also impact to the mapping logic between the XML attributes and elements to DMN definition. As the mapping logic is implemented in DmnDefinitionFactory, the output of DmnParser (DmnModel class) contains the property DmnParser.DmnVersionEnum DmnVersion containing the used/required version. For the sake of simplicity, it's referred as parser version further in the document when documenting the differences or specifics of particular versions. Note: when referring to the version of the library, the term "engine version" is used.

The DmnModel can be transformed directly to the DmnExecutionContext using the DmnExecutionContextFactory overload that gets the DMN Model and encapsulates Model-to-Definition transformation.

var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse(file));

DMN Decision Model Builder

In some cases, it might be easier to define the decision model directly in the code, for example for simple "static" decision model definitions or in cases when the decision model definition needs to be created dynamically. In such cases, the DmnDefinitionBuilder takes place. It provides fluent interface methods to prepare the definition (see details in individual chapters later in this document) and the final method Build that will build the definition of the builder for the use in the execution context.

var definition = new DmnDefinitionBuilder()
                 ....
                .Build();
var ctx = DmnExecutionContextFactory.CreateExecutionContext(definition);

Inputs

DMN input Input represents an external data entering the Engine while evaluating the decision. You can think about it as it's the parameter of the decision to be made.

The input is defined in XML file using the inputData element and recognized by its unique Name taken from name attribute (or from id attribute when the name attribute is missing. The id attribute is mandatory).

<definitions>
  <inputData id="InputData_1upwrsh" name="Age" />
</definitions>

The parser creates the variable used in the Engine context allowing the Engine to access the input parameter. The variable is created with flag IsInputParameter, meaning that the Engine will not allow writing the values into such variable (inputs are immutable). The variable names are being normalized (see later), so it's necessary to keep it in into the consideration when designing the decisions (normalized name needs to be used there). Besides the Name as the unique identifier of input (variable), the non-normalized name as taken from XML is stored in Label property for the information.

The input (parameter) is to be set to the Engine context before evaluating the decision. If not set, its value will be `nu

View on GitHub
GitHub Stars95
CategoryDevelopment
Updated2mo ago
Forks29

Languages

C#

Security Score

100/100

Audited on Jan 18, 2026

No findings