【问题标题】:Sensible pattern for ValidationError class in C#C# 中 ValidationError 类的合理模式
【发布时间】:2010-07-29 15:52:12
【问题描述】:

我即将实现一个类来表示验证错误。该类肯定会包含一个名为 Message 的字符串值,这是向用户显示的默认消息。我还需要一种方法来向程序员表示验证错误是什么。这个想法是应该有一种简单的方法来确定是否发生了特定的验证错误。

实现一个名为 Type 的字符串成员很简单,但要确定 ValidationError 是否属于该类型,我需要记住描述该类型的字符串。

if (validationError.Type == "PersonWithoutSurname") DoSomething();

很明显,我需要一些强类型的东西。枚举会很好:

if (validationError.Type == ValidationErrorType.PersonWithoutSurname) DoSomething();

但考虑到可能存在数百种验证错误,我最终可能会得到一个包含数百个值的丑陋枚举。

我还想到使用子类化:

if (validationError.GetType() == typeof(PersonWithoutSurnameValidationError)) DoSomething();

但是我的类库中充斥着数百个类,每个类大多使用一次。

你们是做什么的?我可以花几个小时为这种事情苦恼。

回答给提出我使用建议的人。枚举建议是要打败的。

【问题讨论】:

    标签: c# design-patterns validation enums fluentvalidation


    【解决方案1】:

    我使用FluentValidation,您可以在其中为每个类设置规则,并为每个属性提供默认或可自定义的消息。

    因为它是一个流畅的框架,所以可以组合规则如:

    RuleFor(customer => customer.Address)
       .NotNull().Length(20, 250).Contains("Redmond")
       .WithMessage(@"Address is required, it must contain 
        the word Redmond and must be between 20 and 250 characters in length.");
    

    Customer 类验证器的典型用法:

    public class CustomerValidator: AbstractValidator<Customer> {
      public CustomerValidator() {
        RuleFor(customer => customer.Surname).NotEmpty();
        RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
        RuleFor(customer => customer.Company).NotNull();
        RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
        RuleFor(customer => customer.Address).Length(20, 250);
        RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
      }
    
      private bool BeAValidPostcode(string postcode) {
        // custom postcode validating logic goes here
      }
    }
    
    Customer customer = new Customer();
    CustomerValidator validator = new CustomerValidator();
    ValidationResult results = validator.Validate(customer);
    
    bool validationSucceeded = results.IsValid;
    IList<ValidationFailure> failures = results.Errors;  
    //Bind these error messages to control to give validation feedback to user; 
    

    【讨论】:

    • 那么检查验证结果看客户姓氏是否为空的代码是什么?
    • 字符串的默认值,即“{propertyname}不能为空。”,这将导致“姓氏不能为空。”
    • 只有在要覆盖默认消息时才使用 WithMessage。默认消息是 resx 文件中的帮助信息,因此您可以根据需要更改这些信息。也有许多语言的带有默认消息的 resx 文件。
    • 如果我有一个 Customer 对象并且我正在检查它是否处于有效状态。如果客户的姓氏为空,我会执行一个代码分支。在 if 条件下我应该写什么?
    • 我喜欢验证逻辑在一个单独的类中的想法,我必须说。整洁。
    【解决方案2】:

    我真的不明白你为什么会遇到这么多麻烦......

    如果您正在执行其验证字段,那么我通常会添加一个正则表达式验证器 & 和一个必填字段验证器。对于某些字段,我确实为我自己的一组规则添加了自定义验证器。但就是这样。对于客户端和服务器端。我所做的只是一个 page.validate 命令,如果抛出错误意味着客户端脚本已被修改,我通常会重新加载页面作为响应。

    另外,如果我想对我使用的单个值进行检查

     System.Text.RegularExpressions.Regex.IsMatch(...
    

    所以还有更多吗?如果有请指出。

    【讨论】:

    • 他正在尝试根据特定类型的验证执行一些操作。这是错误处理,而不是验证。 OP 似乎已经关闭了验证规则,但他担心他会遇到足够多的可能验证错误,因此他希望以一致的格式呈现这些错误类型值。
    • 更多的是向底层域实体添加验证规则,而不是向页面的控件添加验证规则。这样,您可以将业务层移植到另一个前端(例如从 Web 到 Windows),并且仍然可以轻松检查域实体的有效性。
    • 哦,谢谢你让我知道。对不起,我想我在这里没有帮助。
    • 每个回复都是有用的。您进行验​​证的方式与我的不同。谢谢!
    【解决方案3】:

    如果问题是存储类型(尤其是这样您可以添加新类型),那么使用 XML 或数据库驱动的配置文件怎么样?

    使用 app.config,您可以:

    将在代码中调用:

    //Generate the error somehow:
    Validation.ErrorType = 
        ConfigurationManager.AppSettings["PersonWithoutSurnameValidationError"].Value;
    
    //Handle the error
    [Your string solution here]
    

    这样,您可以在代码之外的某个地方记录错误类型,以便更容易记住。另一方面,如果您的主要问题是存储以便获得正确的类型来处理,请坚持使用枚举。

    【讨论】:

    • 使用应用程序配置文件,您将失去业务层的可移植性,尽管我当然可以使用嵌入在业务层项目中的 XML 文件。我真的不需要我可以即时编辑的东西,只需要在代码中易于使用的东西。
    • -1 用于建议在 appsettings 中保存错误。您最好将其存储在存储库(数据库)或.resx 资源文件中。
    猜你喜欢
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 2016-01-10
    • 2011-05-08
    • 1970-01-01
    • 2014-04-23
    相关资源
    最近更新 更多