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

发布于 2024-11-30 04:04:22 字数 662 浏览 0 评论 0原文

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

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

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

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

  • 没有智能感知,并且 XML 文件中的错误很难找到
  • 我们必须编写自定义 XML 解析器
  • 因为此方法需要大量转换,速度非常慢

我的问题:

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


编辑 1)

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

I've been using .Net languages for 4 years. I develop 3 tier and 5 tier applications using WCF, ASP.NET for web applications, and C# for windows applications. Every time I start a project, business rules and validations are a concern.

Where should I place custom validation rules (button-click events, page load, or in setters/getters within my classes)?

If a project is large and there is just a field that instead of 5 characters should be 7 characters - Why should I rebuild the whole project (or business classes project)?

I think if I had a file that had my custom rules, then when a change is needed I could simply place a new rule in it. I have read some articles on the internet that offer an XML based file for this purpose, but this seems problematic because:

  • No Intellisense and errors in the XML file are very hard to find
  • We have to write custom XML parsers
  • Since this method requires numerous casts, it's very slow

My Question:

Is there a design pattern or anything else using .NET methods (Reflection, Expression Trees, Lambda Expressions, Dynamics, Runtime Creation of DLLs, etc.) to have dynamic validation using custom rules?


Edit 1)

What about Attributes? Can we use them with Reflection to Custom validations? Can we validate a property according another property(form example P1 should be P2+1) with this approach?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

海之角 2024-12-07 04:04:22

表示业务规则的最佳方式是在 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>

规则引擎需要解释该规则并推断出相应的含义。

The best way to denote the business rules is in an xml. To take full advantage of this notation, you should start with defining the structure of the rule engine's data model i.e. answer these questions.

  1. What are the rules?
  2. Can the rules be categorized?
  3. Do the rules contain common properties (attributes) like allowed values, format, etc.?

Once this is done, create a dummy rules xml and then derive an xml schema based on this xml. The xsd.exe tool can aid you in creating the schema. It is easier to create the schema if you can use tools like Altova XmlSpy.

As for answers to your specific questions,

  • We can't using Intellisense and if we have error in XML file it is very hard to find it.

Once you have the schema in place, Visual Studio provides ample support in creating the xml (including intellisense and validation).

  • We should write a custom xml parsers

Not required, the XmlSerializer Class provides logic for serialization/deserialization i.e. to convert the rules xml into the rules data model and vice versa.

  • Because this method needs numerous casting ,it's very slow

Well, this is a partly valid point when compared to hard coded rules (rules that are embedded into your assembly as classes), but the flexibility of this approach far outweighs any performance demerits. You do not need to rebuild the solution in case there a change in the rules. In most cases, the performance impact is minimal.

Unless you have a strict performance criteria, the xml approach is the preferred way to implement the rules engine. Remember that the more loosely coupled your architecture is, the higher is the flexibility at runtime but there is negative impact on performance.

Sample rule

<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>

The rules engine needs to interpret this rule and deduce the meaning accordingly.

述情 2024-12-07 04:04:22

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

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

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

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);

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

Take a look at FluentValidation. It uses expressions and you can create conditional validations (e.g. validate these properties if that one meets some criteria). FV is perhaps not as dynamic out of the box, but you gain Intellisense, expressiveness, and type-safety. It's generic nature means it runs reasonably fast. You can inject some of the runtime dynamics by passing in validation delegates or custom validators that can do just about whatever you can think of.

It does mean you'd have to recompile, but you could put the validators in a separate assembly. And it does make sense for the validator not to be on/in the class, because you often find that validation is performed in context. For example, a car might be valid if it has all its wheels. But, if you're trying to drive it and it has no gas battery, then it's "invalid" for driving. That said I'd locate the rules "close" to what they are validating as they are part of your domain.

If you need a rule for a property that depends on one or more properties (including itself) and a custom message if the rule's criteria isn't met, you can do this to. Consider this:

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);

gives a simple comparison, but you could make something much more complex.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文