Skip to content

Scripts

Gabe Stocco edited this page Mar 9, 2022 · 6 revisions

As an alternative to defining a Delegate a Clause can instead specify a C# Script to execute.

Security Note

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.

Using Scripts

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.

Arguments Passed to your Script

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; }
}

Creating a Script Data

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)

Clause with a ScriptData

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)
        }
    }
};

Clause with Script Data that requires additional assemblies and imports.

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
        }
    }
},