【问题标题】:Custom Validator and specifying type of message自定义验证器并指定消息类型
【发布时间】:2011-02-02 04:48:15
【问题描述】:

我在企业验证块中有一个自定义验证。 DoValidate方法如下所示。

protected override void DoValidate(Double objectToValidate, 
    object currentTarget, string key, ValidationResults validationResults)
{
    if (!IsSalMoreThanMinWage(objectToValidate))
    {
        //Here I need to mark this message as a "Warning"
        LogValidationResult(validationResults, 
            "Salary is too low for this state", currentTarget, key);
    }
}

我需要将此验证失败标记为“警告”消息。在前端,当我遍历ValidationResults 集合并获取ValidationResult 对象时,我需要识别和分组不同类型的消息并以不同方式呈现它们。

我的问题是 - 如何将失败标记为警告?

【问题讨论】:

    标签: c# .net validation enterprise-library


    【解决方案1】:

    您可以使用ValidationResultTag 属性。 "The meaning for a tag is determined by the client code consuming the ValidationResults."

    如果你正在使用配置,那么你可以在你的配置文件中指定标签:

    <validator lowerBound="0" lowerBoundType="Inclusive" 
    upperBound="255" upperBoundType="Inclusive" negated="false" messageTemplateResourceName="" messageTemplateResourceType="" 
    messageTemplate="Oops a warning occurred" 
    tag="Warning" type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.StringLengthValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
    name="My Validator" />
    


    或者使用属性设置标签:

    [StringLengthValidator(5, 50, Ruleset = "RuleSetA", Tag="Warning")]
    


    如果您想以编程方式执行此操作,则必须创建一个新的验证结果,因为 Tag 属性是只读的:

    ValidationResults newResults = new ValidationResults();
    
    foreach (ValidationResult vr in validationResults)
    {
        newResults.AddResult( new ValidationResult( 
            vr.Message, vr.Target, vr.Key, "Warning", vr.Validator, vr.NestedValidationResults ) );
    }
    


    然后在前端你可以检查一下ValidationResult的Tag属性看看是不是警告:

    foreach (ValidationResult vr in validationResults)
    {
        if (string.Compare(vr.Tag, "Warning") == 0)
        {
            DisplayWarning(vr.Message);
        }
        else
        {
            DisplayError(vr.Message);
        }
    }
    


    显然,您可以更好地抽象它,汇总错误和警告等。

    更新

    我们没有与您相同的要求,但我们会做类似的事情。不幸的是,我知道执行您所说的条件验证类型的唯一方法是使用 RuleSet。

    我们所做的是使用规则集的命名约定并在运行时构造规则集名称。如果 RuleSet 存在,那么我们运行验证器。你可以为你的警告做类似的事情。所以你可以有两个 RuleSet:

    • RuleSet_Salary_Update
    • RuleSet_Salary_Update_Warning

    然后根据是否要运行警告验证来检索验证器列表:

    public static List<Validator<T>> CreateValidators<T>(bool shoulIncludeWarning, RuleSetType rulesetType)
    {
         if (shouldIncludeWarning)
         {
             // Get warning validator if any
         }
    
         // Get Default validator (if any)
    }
    

    RuleSetType 是一个具有不同类型规则(例如 Select、Insert、Update、Delete、PrimaryKey 等)的枚举。

    【讨论】:

    • @Tuzo - 是的,这就是我最终所做的。我希望 VAB 制造商对标签使用不同的数据类型。我想使用一个枚举,但最终不得不做一些将字符串标签转换为枚举的肮脏工作。就像 Steven 指出的那样,一旦用户取消了警告,我需要一种方法来再次运行验证,但现在忽略警告。我想在不使用规则集的情况下执行此操作(除非有一种方法可以为单个验证器指定多个规则集)
    • @Tuzo - 关于你的更新 - 你说“使用规则集的命名约定并在运行时构造它们”你如何在运行时命名规则集?
    • 抱歉,我说的是在运行时使用命名约定构造 RuleSet names。不自己动态创建规则集。
    • 使用Tag 是一个不错的选择。我错过了。
    【解决方案2】:

    简答:

    创建一个非默认规则集并将其命名为“警告”。

    长答案:

    验证应用程序块支持“规则集”的概念。您可以创建一个名为“警告”的规则集。如何使用它取决于您的架构和界面,但这里有一个想法。

    这有点取决于您是否总是希望同时显示错误和警告,或者只在有错误时显示错误,否则显示警告或保存。当出现警告时,用户需要能够说“是的,我确定,保存它!”然后你需要通过抑制错误来保存更改。

    当您采用这种方法时,您可以抛出包含 ValidationResult 对象的异常(例如 ValidationException)。向异常添加一个属性,说明结果是警告还是错误(当您决定在出现错误时不显示任何警告时,您可以这样做)。

    在您的表示层中,您执行以下操作:

    Button_Save(object sender, EventArgs e)
    {
        this.Save(ValidationMode.Default);
    }
    
    Button_HellYesSuppresWarningsAndSave(object sender, EventArgs e)
    {
        this.Save(ValidationMode.SuppressWarnings);
    }
    
    
    private Save(ValidationMode mode)
    {
        try
        {
            ServiceLayer.Save(mode);
        }
        catch (ValidationException ex)
        {
            if (ex.ResultType == ValidationResultType.Warnings)
            {
                ShowWarningsAndAskIfSure(ex.Errors);
            }
            else
            {
                ShowErrorsAndTellUserNeedsToFix(ex.Errors);
            }
        }
    }
    

    在业务层你需要这样:

    public void Save(ValidationMode mode)
    {
        Validate(ValidationResultType.Errors);
    
        if (!mode == ValidationMode.SuppressWarnings)
        {
            Validate(ValidationResultType.Warnings);
        }
    }
    
    private void Validate(ValidationResultType type)
    {
        var objectToValidate;
        var ruleset = type == ValidationResultType.Errors ? "default" : "warnings";
        var validator = ValidationFactory
           .CreateValidator(objectToValidate.GetType(), ruleset);
    
        var results = validator.Validate();
        if (!results.IsValid)
        {
            throw new ValidationException(results, type);
        }
    }
    

    我希望这是有道理的。

    【讨论】:

    • @Steven - 这与我试图实现的目标相似。但是,我已经在使用规则集来定义基于业务规则的其他分组。除了规则集,还有其他方式可以说 - 嘿,用户已经禁止了警告,所以不要运行任何标记为警告的验证?我遇到的另一个问题是我添加的代码 sn-p 是我正在处理的自定义验证器的子集。我正在处理的有 2 个验证 - 1 个是警告,1 个是错误。两者都包含在 DoValidate 方法中。在我看来,这个验证器需要分成错误和警告
    • @Steven - 一个不相关的问题。如果结果无效,为什么要抛出异常?虽然这可行,但我总是在代码无法恢复的极端情况下抛出异常。副作用之一是,如果您在应用程序中使用任何日志记录块,所有这些异常都会被记录在日志中。
    • @user102533:“有没有其他方法可以 [...] 不运行任何标记为警告的验证?”。据我所知,没有其他方法可以将验证标记为警告。我认为规则集是唯一可行的方法。
    • @user102533:“如果结果无效,你为什么要扔前任?”。原因很简单,因为无效的结果是必须引起注意的。您最不想看到的是开发人员调用 Save 并忘记检查您的数据是否实际保存。没有规则说异常只能在不可恢复的情况下使用。此外,异常通常仅在未处理时才会被记录。在我回答的Save 方法示例中,您会看到异常得到处理。如果您使用分析记录每个抛出的异常,您的日志只会变得混乱。
    • @user102533:正如 Tuzo 指出的,您可以在验证后对Tag 使用标签和过滤器。但是,该标签不能用于阻止运行验证。因此,当您进行性能密集型验证(即转到数据库)并且不想在不需要时运行时,这可能是一个问题。为此,我认为规则集是您唯一的希望。
    猜你喜欢
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    • 2017-12-06
    • 1970-01-01
    相关资源
    最近更新 更多