aspnetboilerplate - ABP 中 NRules 的属性注入(inject)

标签 aspnetboilerplate nrules

我正在使用 ABP Boilerplate 6.0 并将 NRules 与我们的平台集成。

  • 我能够使下面的规则起作用,但问题是我不能在规则条件中使用注入(inject)的“_questionResponseRepository”,因为只有在满足规则条件后,才会解决依赖关系。
  • 我想使用“_questionResponseRepository”从数据库中获取关键字列表,并在规则匹配条件
  • 中使用这些词

    电话号码
    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)到规则中。
    有两种方法可以将依赖项注入(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();
    
  • 从规则引擎外部的存储库中检索关键字,并将它们作为事实插入到 session 中。这实际上是首选,因为您可以更好地控制与外部数据的交互。此外,您可以将关键字放入具有高效查找性能的数据结构中(例如 trie)。
    在这种情况下,您不需要规则激活器或向容器注册规则,就像选项 #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();
    
  • 您也可以将存储库本身作为事实插入,然后在规则中匹配它,但我不建议这样做,所以我会坚持使用选项 #1 或 #2。
  • 关于aspnetboilerplate - ABP 中 NRules 的属性注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65469249/

    相关文章:

    c# - 如何在 IIS 上运行的 dotnet 核心应用程序中获得可见性/调试高内存使用率

    c# - NRules:在具有自定义基类的规则上使用 DSL 扩展的问题

    c# - NRules:匹配集合

    nrules - 如何使用 NRules 创建验证规则?

    ubuntu - 如何在 ubuntu 中解决这些警告?

    asp.net-core-mvc - 数据未根据 abp.ajax 请求发送到服务器

    c# - 抑制工作单元事务中的错误

    asp.net-core - 如何在 ABP Core Zero 中使用多个数据库?

    c# - 如何在 NRules 中进行最佳写入规则定义