ABP中的NRule的属性注入 [英] Property Injection for NRules within ABP

查看:68
本文介绍了ABP中的NRule的属性注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ABP Boilerplate 6.0,并且已将NRule与我们的平台集成.

I am using ABP Boilerplate 6.0 and have integrated NRules with our platform.

  1. 我能够使下面的规则起作用,但是问题是我不能在规则条件内使用注入的'_questionResponseRepository',因为只有在满足规则条件后,才可以解决依赖关系./li>
  2. 我想使用"_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的规则匹配条件中,有几种方法可以使用外部信息(在本例中为DB的关键字).

There are a few ways to use external information (in this case keywords from the DB) in the rule's match condition in NRules.

  1. 将相应的存储库/服务注入规则.有两种将依赖项注入规则的方法.在规则类实例化期间,或通过Dependency.Resolve DSL在规则运行时.正如您所指出的,由于Dependency.Relsove只能在规则(操作)的右侧使用,因此不适用于此用例.但是,您仍然可以在规则实例化期间将依赖项注入到规则中.您需要在容器中注册规则类型本身,实现IRuleActivator来通过该容器解析规则,并在加载规则时设置RuleRepository.RuleActivator.如果存储库和规则都在同一容器中注册,则规则将被注入依赖项(您可以使用属性注入或构造函数注入,这取决于您注册类型的方式).然后,您可以只在表达式中使用依赖项.我没有您的所有代码,因此,假设情况如下所示.在这里,我假设有一个 Keyword 实体的存储库,可用于从数据库中获取关键字.我也在使用构造函数注入,但是对于属性注入也可以使用.
  1. Inject the corresponding repository/service into the rule. There are two ways to inject dependencies into rules. During instantiation of rule classes, or at rule's run time via Dependency.Resolve DSL. Since Dependency.Relsove, as you pointed out, can only be used on the right-hand side of the rule (actions), it's not suitable for this use case. But you can still inject the dependency into the rule during the rule's instantiation. What you need to do here is to register the rule type itself with the container, implement an IRuleActivator to resolve rules via that container, and set the RuleRepository.RuleActivator when loading the rules. If both the repository and the rule are registered with the same container, the rule will get injected with the dependency (you can use either property or constructor injection, depending on how you registered the types). Then you can just use the dependency in the expressions. I don't have all your code, so hypothetically, it would look something like below. Here I'm assuming there is a repository of a Keyword entity that can be used to fetch keywords from the DB. I'm also using constructor injection, but the same would work for property injection.

    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方法的某个位置或相应控制器的某个位置:

Then somewhere in your Trigger method or somewhere in a corresponding controller:

    var dto = new QuestionResponseDto(...);
    _session.Insert(dto);
    _session.Fire();

  1. 从规则引擎外部的存储库中检索关键字,然后将它们作为事实插入到会话中.实际上,这是首选方法,因为您可以更好地控制与外部数据的交互.另外,您可以将关键字放入具有高效查找性能的数据结构中(例如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方法的某个位置或相应控制器的某个位置:

Then somewhere in your Trigger method or somewhere in a corresponding controller:

    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.

这篇关于ABP中的NRule的属性注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆