Hi,
we are very interested in NRules possibilities, but our use case is very special and I would like your point of view on what is possible or not.
We are developing a Unity3D app on iOS. This app is consuming data produced by visual editors running on Windows desktop.
We would like to use power of rules engine mechanism, and be able to design rules on windows, and use them in the iOS app.
We have tried to use directly rules engines on the ios but of course we hit the 'compile' limitation for code generation on the type of aot platforms.
My question is : could we eventually think about split NRules behavior in two steps :
on windows use it to compile rules and get a factory
then find a way to serialize this factory instance (as dylib ?), put it on database
then on iOS deserialize it and continue your "Getting Started" example , using compiled rules to avoid code generation on this platform
so, to illustrate it using your "Getting Started" example :
On Windows
//Load rules
var repository = new RuleRepository();
repository.Load(x => x.From(typeof(PreferredCustomerDiscountRule).Assembly));
//Compile rules
var factory = repository.Compile();
Find a way to save compiled rules code
and On iOS :
//retreive compiled rules code
var factory = new FactoryFromSomething()
//Create a working session
var session = factory.CreateSession();
//Load domain model
var customer = new Customer("John Doe") {IsPreferred = true};
var order1 = new Order(123456, customer, 2, 25.0);
var order2 = new Order(123457, customer, 1, 100.0);
//Insert facts into rules engine's memory
session.Insert(customer);
session.Insert(order1);
session.Insert(order2);
//Start match/resolve/act cycle
session.Fire();
Hope this strange use case is clear and hope you can help us :)
Hello everyone,
I'm goonna start my thesis soon, my thesis is about integration of rule engine to create BIM models in Revit(AutoCAD). to create models in revit I use revit API(Also implemented in .Net). I have created ASP.Net core application to store all the data required to create a house model in revit. Revit APIs will communicate through REST APIs.
Everytime when I pull the data from database to give information to revit APIs I have to apply rules based on the user configuration of the house and modify the input data based on the rules. So I have started learning NRules and reading the Documentation. I would be very helpful to be sussceful in my thesis by getting suggestion about learning NRules and also some can I achiche everything in applying rules using NRules?
using RuleExpert.BimModels;
using RuleExpert.RuleModels;
using System;
namespace RuleExpert
{
class Program
{
static void Main(string[] args)
{
var repository = new RuleRepository();
repository.Load(x => x.From(typeof(FloorLengthAndWidthModifiedRule).Assembly));
var factory = repository.Compile();
var session = factory.CreateSession();
var userInput = new UserInputModel() { HouseName = "flair", IsModefiedLengthAndWidth = true, X = 10, Y = 11 };
session.Insert(userInput);
session.Fire();
Console.WriteLine("Hello World!");
}
}
}
namespace RuleExpert.RuleModels
{
[Name("MyRule"), Description("Test rule that demonstrates metadata usage")]
class FloorLengthAndWidthModifiedRule : Rule
{
public override void Define()
{
When()
.Match<UserInputModel>( c => c.IsModefiedLengthAndWidth == true);
Then()
.Do(c=>NotifyChange());
}
public static void NotifyChange()
{
System.Console.WriteLine("Length and width are changed");
}
}
}
@snikolayev Is there any way to have an "optional" clause in the NRules DSL that would serve only to fill a value if the clause evaluates to true? I know this would be possible via an Or clause where one of the branches of the Or always evaluates true, but I'd prefer not to have the rule fire twice if the optional branch evaluates true.
e.g. see this pseudocode:
Define() {
bool foundOptionalFact = false;
When()
// Required clause
.Exists<FactType>(fact => fact.PassesTest)
// Optional clause
.Optional(x => x
.And(xx => xx
.Exists<FactType>(fact => fact.PassesTest)
.Let(() => foundOptionalFact , () => true)));
// Then will run as long as long the required clause is evaluated true
Then(ctx => (foundOptionalFact));
}
Hey @larrybehlang_gitlab - the way you handle optional facts normally is via a Query. Something like this:
Fact1 requiredFact = default;
Fact2 optionalFact = default;
When()
.Match<Fact1>(() => requiredFact, c => c.Predicate)
.Query(() => optionalFact, x => x
.Match<Fact2>(o => o.Predicate)
.Collect()
.Select(c => c.FirstOrDefault()));
You can also wrap this into an extension method, call it MatchOptional and have a shorthand for it
NRules.Language
like there is for Fluent Rules DSL
https://github.com/NRules/NRules/wiki/Fluent-Rules-DSL
NRules.Language
for NRules, and I have a question - is there a way to organise my rules in to separate RuleSets
(like the option present in the DSL version of NRules)? I tried adding ruleset
in the rul file but it doesn't like that.
Is there a way to write DLC-extensions in a way that allows passing the value bound to a variable via Let
to the extension?
For example, I would like to change
public class MyRule : Rule
{
public override void Define()
{
MyClass obj = null;
When()
// [...]
.Let(() => obj, () => GetMyClassInstance())
.Having(() => ValidateMyClass(obj))
// [...]
}
}
into
public class MyRule : Rule
{
public override void Define()
{
MyClass obj = null;
When()
// [...]
.Get(() => obj)
.Validate(obj)
// [...]
}
}
public static class DslExtensions
{
public static ILeftHandSideExpression Get(this ILeftHandSideExpression lhs, Expression<Func<MyClass>> alias)
{
return lhs
.Let(alias, () => GetMyClassInstance())
;
}
public static ILeftHandSideExpression Validate(this ILeftHandSideExpression lhs, MyClass objectToValidate)
{
return lhs
.Having(() => ValidateMyClass(objectToValidate)) // objectToValidate is always null here
;
}
}
However, this will not work because objectToValidate
will always be null.
It will "work" if I either rename the parameter to be the same as in the Rule ("obj
") or remove the parameter alltogether and instead add a local object by that name to the Validate
function:
public static ILeftHandSideExpression Validate(this ILeftHandSideExpression lhs, MyClass obj)
{
return lhs
.Having(() => ValidateMyClass(obj)) // this "works"
;
}
public static ILeftHandSideExpression Validate(this ILeftHandSideExpression lhs)
{
MyClass obj = null;
return lhs
.Having(() => ValidateMyClass(objectToValidate)) // so does this
;
}
This obviously removes quite a bit of flexibility from working with DSL-extensions so I suspect there is some way to do what I am trying here that I am not aware of?