我正在使用 ABP Boilerplate 6.0 并将 NRules 与我们的平台集成。
电话号码
public WasteManagementManager(
IRepository<WasteBirthCertificateBlock, long> wasteBirthCertificateBlockRepository,
IRepository<WasteBirthCertificateChain, long> wasteBirthCertificateChainRepository,
ISession nRuleSession,
ISessionFactory nRuleSessionFactory,
ILogger log
)
{
_wasteBirthCertificateBlockRepository = wasteBirthCertificateBlockRepository;
_wasteBirthCertificateChainRepository = wasteBirthCertificateChainRepository;
_nRuleSession = nRuleSession;
_nRuleSessionFactory = nRuleSessionFactory;
_log = log;
}
public void Trigger()
{==>
When I am in debug, _questionResponseRepository is NOT NUll. I'm trying inject it as a fact but that is not property injection .. I'm just trying one way or the other to get it working
_nRuleSession.Insert(_questionResponseRepository);
_nRuleSession.Fire();
}
规则代码 namespace SagerSystems.AI.WasteManagements.NRules
{
[Name("Track Explosive Substances Rule")]
public class TrackExplosiveSubstancesRule : Rule
{
private string[] _listOfExplosiveKeyWords = new string[] { "H3O", "N2" };
public IRepository<QuestionResponse, long> _questionResponseRepository { get; set; }
public TrackExplosiveSubstancesRule()
{
**This does NOT work** (the value remains null)
Dependency()
.Resolve(() => _questionResponseRepository);
}
public override void Define()
{
*This does work* but only after the rule fires)
Dependency()
.Resolve(() => _questionResponseRepository);
When()
.Match(() => questionResponseDto, c => CheckKeyWord(c));
Then()
.Do(ctx => Console.WriteLine(“Test Condition Works”))
}
private bool CheckKeyWord(QuestionResponseDto questionResponseDto)
{
==> How do I user ‘questionResponseRepository’
var isKeyWord=
_listOfExplosiveKeyWords.Any(c => questionResponseDto.QuestionText.Contains(c));
return isKeyWord;
}
}
}
最佳答案
有几种方法可以在 NRules 的规则匹配条件中使用外部信息(在本例中是来自数据库的关键字)。
有两种方法可以将依赖项注入(inject)规则。在规则类的实例化期间,或在规则运行时通过 Dependency.Resolve DSL。正如您所指出的,由于 Dependency.Relsove 只能用于规则(操作)的右侧,因此不适合此用例。但是您仍然可以在规则实例化期间将依赖项注入(inject)到规则中。
这里需要做的是将规则类型本身注册到容器中,实现一个 IRuleActivator 来通过该容器解析规则,并在加载规则时设置 RuleRepository.RuleActivator。如果存储库和规则都在同一个容器中注册,则规则将被注入(inject)依赖项(您可以使用属性或构造函数注入(inject),具体取决于您注册类型的方式)。然后你可以在表达式中使用依赖。
我没有你所有的代码,所以假设它看起来像下面这样。这里我假设有一个
Keyword
的存储库可用于从数据库中获取关键字的实体。我也在使用构造函数注入(inject),但同样适用于属性注入(inject)。 public class RuleActivator : IRuleActivator
{
private readonly IIocResolver _iocResolver;
public RuleActivator(IIocResolver iocResolver)
{
_iocResolver = iocResolver;
}
public IEnumerable<Rule> Activate(Type type)
{
yield return (Rule)_iocResolver.Resolve(type);
}
}
public class RulesEngineModule : AbpModule
{
public override void Initialize()
{
//Find rule classes
var scanner = new RuleTypeScanner();
scanner.AssemblyOf<TrackExplosiveSubstancesRule>();
var ruleTypes = scanner.GetRuleTypes();
//Register rule classes with the container
foreach (var ruleType in ruleTypes)
{
IocManager.Register(ruleType);
}
//Load rules into the repository; use a rule activator to resolve rules via the container
var repository = new RuleRepository {Activator = new RuleActivator(IocManager)};
repository.Load(x => x.From(s => s.Type(ruleTypes)));
//Compile rules into the factory
var factory = repository.Compile();
//Register session factory instance
IocManager.IocContainer.Register(
Component.For<ISessionFactory>().Instance(factory));
//Register session as a delegate that creates a new instance from a factory
IocManager.IocContainer.Register(
Component.For<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>().CreateSession()).LifestyleTransient());
}
}
[Name("Track Explosive Substances Rule")]
public class TrackExplosiveSubstancesRule : Rule
{
private readonly IRepository<Keyword, long> _keywordRepository;
public TrackExplosiveSubstancesRule(IRepository<Keyword, long> keywordRepository)
{
_keywordRepository = keywordRepository;
}
public override void Define()
{
QuestionResponseDto questionResponseDto = default;
When()
.Match(() => questionResponseDto, c => ContainsKeyword(c));
Then()
.Do(ctx => Console.WriteLine("Test Condition Works"));
}
private bool ContainsKeyword(QuestionResponseDto questionResponseDto)
{
var keywords = _keywordRepository.GetAll().ToList();
var hasKeyWord = keywords.Any(keyword => questionResponseDto.QuestionText.Contains(keyword.Value));
return hasKeyWord;
}
}
然后在您的 Trigger 方法中或相应 Controller 中的某处: var dto = new QuestionResponseDto(...);
_session.Insert(dto);
_session.Fire();
在这种情况下,您不需要规则激活器或向容器注册规则,就像选项 #1 一样,因为所有输入都作为事实出现在规则中,因此实际上没有外部依赖项。
例如:
public class KeywordSet
{
private readonly Keyword[] _keywords;
public KeywordSet(IEnumerable<Keyword> keywords)
{
_keywords = keywords.ToArray();
}
public bool ContainsAny(string value)
{
return _keywords.Any(keyword => value.Contains(keyword.Value));
}
}
[Name("Track Explosive Substances Rule")]
public class TrackExplosiveSubstancesRule : Rule
{
public override void Define()
{
KeywordSet keywordSet = default;
QuestionResponseDto questionResponseDto = default;
When()
.Match(() => keywordSet)
.Match(() => questionResponseDto, c => keywordSet.ContainsAny(c.QuestionText));
Then()
.Do(ctx => Console.WriteLine("Test Condition Works"));
}
}
然后在您的 Trigger 方法中或相应 Controller 中的某处: var keywords = _keywordRepository.GetAll().ToList();
var keywordSet = new KeywordSet(keywords);
_session.Insert(keywordSet);
var dto = new QuestionResponseDto(...);
_session.Insert(dto);
_session.Fire();
关于aspnetboilerplate - ABP 中 NRules 的属性注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65469249/