使用自定义规则进行动态验

Ari*_*ian 4 .net c# design-patterns business-rules c#-4.0

我已经使用.Net语言已有4年了.我使用WCF,ASP.NET用于Web应用程序和C#用于Windows应用程序开发3层和5层应用程序.每次我开始一个项目时,业务规则和验证都是一个问题.

我应该在哪里放置自定义验证规则(按钮单击事件,页面加载,或在我的类中的setter/getters)?

如果项目很大并且只有一个字段而不是5个字符应该是7个字符 - 为什么要重建整个项目(或业务类项目)?

我想如果我有一个拥有自定义规则的文件,那么当需要进行更改时,我可以简单地在其中放置一条新规则.我已经在互联网上阅读了一些为此目的提供基于XML的文件的文章,但这似乎有问题,因为:

  • XML文件中没有Intellisense和错误很难找到
  • 我们必须编写自定义XML解析器
  • 由于这种方法需要大量的演员阵容,因此速度非常慢

我的问题:

是否有使用.NET方法(反射,表达式树,Lambda表达式,动态,DLL的运行时创建等)的设计模式或其他任何东西,以使用自定义规则进行动态验证?


编辑1)

属性怎么样?我们可以将它们与反射到自定义验证一起使用吗?我们可以使用这种方法根据另一个属性(形式示例P1应该是P2 + 1)来验证属性吗?

Dev*_*van 5

表示业务规则的最佳方法是使用xml.要充分利用这种表示法,您应该首先定义规则引擎数据模型的结构,即回答这些问题.

  1. 规则是什么?
  2. 规则可以分类吗?
  3. 规则是否包含常用属性(属性),如允许值,格式等?

完成此操作后,创建一个虚拟规则xml,然后根据此xml派生一个xml模式.该XSD.EXE工具可以帮助您创建模式.如果您可以使用Altova XmlSpy等工具,则更容易创建架构.

至于你的具体问题的答案,

  • 我们不能使用Intellisense,如果我们在XML文件中有错误,很难找到它.

一旦你有了架构,Visual Studio就会在创建xml时提供足够的支持(包括intellisense和validation).

  • 我们应该编写一个自定义的xml解析器

不需要,XmlSerializer类提供序列化/反序列化的逻辑,即将规则xml转换为规则数据模型,反之亦然.

  • 因为这种方法需要多次铸造,所以速度非常慢

嗯,与硬编码规则(作为类嵌入到程序集中的规则)相比,这是一个部分有效的点,但这种方法的灵活性远远超过任何性能缺点.如果规则发生更改,则无需重建解决方案.在大多数情况下,性能影响很小.

除非您有严格的性能标准,否则xml方法是实现规则引擎的首选方法.请记住,架构越松散耦合,运行时的灵活性越高,但对性能产生负面影响.

示例规则

<RulesEngine>
  <Rules>
    <Rule Id="Rule1">
      <Function>
        <Equals>
          <Property name="Property1" classId="MyClassId"/>
            <Sum>
              <Property name="Property2" classId="MyClassId"/>
              <Constant type="UInt16" value="1"/>
            </Sum>
          </Equals>
        </Function>
      </Rule>
    </Rules>
    <Classes>
    <Class name="MyNamespace.MyClass" Id="MyClassId">
      <Property name="Property1" type="UInt16"/>
      <Property name="Property2" type="UInt16"/>
    </Class>
  </Classes>
</RulesEngine>
Run Code Online (Sandbox Code Playgroud)

规则引擎需要解释此规则并相应地推断其含义.


Kit*_*Kit 5

看看FluentValidation。它使用表达式和(例如验证您可以创建条件验证这些,如果性能一个符合某些标准)。FV 可能不是开箱即用的动态,但您可以获得智能感知、表现力和类型安全性。它的通用性意味着它运行得相当快。您可以通过传入验证委托或自定义验证器来注入一些运行时动态,它们几乎可以做您能想到的任何事情。

这确实意味着您必须重新编译,但您可以将验证器放在单独的程序集中。并且验证器不在类上/在类中确实有意义,因为您经常发现验证是在context 中执行的。例如,如果一辆汽车有所有的轮子,它可能是有效的。但是,如果您尝试驾驶它并且它没有燃气电池,那么它对于驾驶来说是“无效的”。也就是说,我会将规则定位为“接近”它们正在验证的内容,因为它们是您域的一部分。

如果您需要为依赖于一个或多个属性(包括其自身)的属性制定规则,并且在不满足规则的条件时需要自定义消息,您可以执行此操作。考虑一下:

RuleFor(x => x.P1)
    .Must(x => x.P1 > x.P2)
    .Message("P1 must be one more than P2. P1 was {0}; P2 was {1}", x=>x.P1, x=>x.P2);
Run Code Online (Sandbox Code Playgroud)

给出了一个简单的比较,但您可以制作更复杂的东西。

  • 当然,这里是你如何做你想做的,如果不满足规则的标准,自定义消息:`RuleFor(x =&gt; x.P1).Must(x =&gt; x.P1 == x.P2 + 1).Message("P1必须比P2大1。P1是{0};P2是{1}", x=&gt;x.P1, x=&gt;x.P2);` (3认同)