-
Notifications
You must be signed in to change notification settings - Fork 19
Scripts
As an alternative to defining a Delegate a Clause can instead specify a C# Script to execute.
Enabling Scripting means trusting that the Rules you are processing are not malicious. Scripts are not sandboxed and allow execution of arbitrary code.
To ensure that scripting isn’t enabled by mistake you will need to also include the Microsoft.CST.OAT.Scripting package and also set the flag to enable scripts when instantiating your analyzer.
To provide a script set the Operation of the Clause to Custom, and the Script
property to a ScriptData
containing your code.
To enable Scripts, set RunScripts
to true in the Analyzer.
var analyzer = new Analyzer(new AnalyzerOptions(runScripts: true));
Running Scripts is not supported in the GUI.
Your script will be passed an OperationArguments class with these fields to process.
public class OperationArguments
{
public Clause Clause { get; }
public object? State1 { get; }
public object? State2 { get; }
public IEnumerable<ClauseCapture>? Captures { get; }
}
To create a ScriptData
object to attach to a clause use the ScriptData constructor with your code, imports and references.
Imports is an enumerable of strings containing statements to import, for example System.IO
.
References is an enumerable of strings containing names of assemblies to reference, for example MyAssembly
for MyAssembly.dll
.
public ScriptData(string code, IEnumerable<string>? imports = null, IEnumerable<string>? references = null)
To create a clause that uses your Script assign the ScriptData
you've created to the Script
property in the Clause.
var lambda = @"return new OperationResult(State1 is true, null);";
var rule = new Rule("Lambda Rule")
{
Clauses = new List<Clause>()
{
new Clause(Operation.Custom)
{
Script = new ScriptData(lambda)
}
}
};
From the Weigh Station example in the Walkthrough we need to include the additional assembly references to get the objects from the test namespace and the includes for that namespace as well.
new VehicleRule("Overweight")
{
Cost = 50,
Severity = 9,
Expression = "Overweight",
Target = "Vehicle",
Clauses = new List<Clause>()
{
new Clause(Operation.Custom)
{
Label = "Overweight",
Script = new ScriptData(code: @"
if (State1 is Vehicle vehicle)
{
var res = vehicle.Weight > vehicle.Capacity;
if ((res && !Clause.Invert) || (Clause.Invert && !res))
{
// The rule applies and is true and the capture is available if capture is enabled
return new OperationResult(true, Clause.Capture ? new TypedClauseCapture<int>(Clause, vehicle.Weight, State1, State2) : null);
}
}
return new OperationResult(false, null);",
imports: new List<string>() {"System", "Microsoft.CST.OAT.Tests"},
references: new List<string>(){ "OAT.Tests" }),
Capture = true
}
}
},