首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ABP中NRules的属性注入

ABP中NRules的属性注入
EN

Stack Overflow用户
提问于 2020-12-27 18:44:05
回答 1查看 463关注 0票数 2

我使用的是ABP样板6.0,并已将NRules与我们的平台集成。

  1. I可以让下面的规则工作,但问题是我不能在规则条件内使用注入的‘_questionResponseRepository’,因为只有在满足规则条件之后,才能解决依赖关系。
  2. I希望使用‘_questionResponseRepository’从数据库中获取关键字列表并在规则匹配条件

中使用这些单词。

调用代码

代码语言:javascript
复制
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();
 }

规则代码

代码语言:javascript
复制
 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;
            }
        }
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-01 00:05:54

在NRules中规则的匹配条件中,有几种方法可以使用外部信息(在本例中是来自DB的关键字)。

  1. 将相应的存储库/服务注入规则。将依赖项注入规则有两种方法。在规则类实例化期间,或在规则运行时通过Dependency.Resolve DSL。因为正如您指出的那样,Dependency.Relsove只能在规则(操作)的右侧使用,所以它不适合这个用例。但是,在规则的实例化过程中,仍然可以将依赖项注入规则。这里需要做的是将规则类型本身注册到容器中,实现一个IRuleActivator来通过该容器解析规则,并在加载规则时设置RuleRepository.RuleActivator。如果存储库和规则都在同一个容器中注册,规则将被注入依赖项(根据注册类型的方式,可以使用属性或构造函数注入)。然后,您可以只使用表达式中的依赖项。我没有你所有的代码,所以假设,它看起来如下所示。这里我假设有一个Keyword实体的存储库,可以用来从DB中获取关键字。我也在使用构造函数注入,但同样适用于属性注入。

代码语言:javascript
复制
    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;
        }
    }

然后在触发器方法中的某个位置或相应的控制器中的某个位置:

代码语言:javascript
复制
    var dto = new QuestionResponseDto(...);
    _session.Insert(dto);
    _session.Fire();

  1. 从规则引擎之外的存储库中检索关键字,并将它们作为事实插入会话。这实际上是首选的,因为您可以更好地控制与外部数据的交互。此外,您还可以将关键字放入具有高效查找性能的数据结构中(例如,trie)。在这种情况下,您不需要规则激活器,也不需要将规则注册到容器中,就像选项1一样,因为所有输入都是事实,因此实际上不存在外部依赖关系。例如:

代码语言:javascript
复制
    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"));
        }
    }

然后在触发器方法中的某个位置或相应的控制器中的某个位置:

代码语言:javascript
复制
    var keywords = _keywordRepository.GetAll().ToList();
    var keywordSet = new KeywordSet(keywords);
    _session.Insert(keywordSet);
    
    var dto = new QuestionResponseDto(...);
    _session.Insert(dto);
    _session.Fire();

  1. 您也可以将存储库本身作为一个事实插入,然后在规则中匹配它,但是我不建议这样做,所以我将坚持选择#1或#2。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65469249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档