6

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

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

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

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

  • XML 文件中没有 Intellisense 和错误很难找到
  • 我们必须编写自定义 XML 解析器
  • 由于此方法需要多次转换,因此非常慢

我的问题:

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


编辑 1)

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

4

2 回答 2

6

表示业务规则的最佳方式是在 xml 中。要充分利用这种表示法,您应该从定义规则引擎数据模型的结构开始,即回答这些问题。

  1. 都有些什么样的规矩?
  2. 规则可以分类吗?
  3. 规则是否包含常见的属性(属性),例如允许的值、格式等?

完成此操作后,创建一个虚拟规则 xml,然后基于此 xml 派生一个 xml 模式。xsd.exe工具可以帮助您创建架构。如果您可以使用Altova XmlSpy 之类的工具,则更容易创建架构。

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

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

架构就绪后,Visual Studio 会为创建 xml 提供充足的支持(包括智能感知和验证)。

  • 我们应该编写一个自定义的 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>

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

于 2011-08-16T18:18:37.213 回答
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);

给出了一个简单的比较,但你可以做一些更复杂的事情。

于 2011-08-16T18:37:04.747 回答