0

I have a class TestClass and I want to customize the validation message instead of default one.

TestClass is the post model in the controller which inherits from ControllerBase.

Here is what I've tried:

TestClass.cs

public class TestClass
{       
    [TestAtrribute(1.00, 99.99)]
    public double TestNumber { get; set; }
}

TestAttribute.cs

public class TestAttribute : ValidationAttribute
{
    private double _min;
    private double _max;

    public TestAttribute(double min, double max)
    {
        _min = min;
        _max = max;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var error = $"{value} is invalid, must be between {_min} and {_max}";
        try
        {
            var convertNum = Convert.ToDouble(value);
            if (convertNum < _min || convertNum > _max)                
                return new ValidationResult(errorMessage);                
        }
        catch (Exception)
        {
            return new ValidationResult(error);
        }

        return ValidationResult.Success;
    }
}

However, when I post string value, my custom attribute doesn't work. It returns the default message:

Could not convert string to double: test. Path 'TestClass.TestNumber', line 36, position 22.

What I expect is:

test is invalid, must be between 1.00 and 99.99

Please let me know how I can solve it.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
anhtv13
  • 1,636
  • 4
  • 30
  • 51
  • When I do debug, it doesn't come to my IsValid method. I believe some validations have been done before it can get to my IsValid method. – anhtv13 Feb 07 '22 at 10:52

2 Answers2

0

Please override FormatErrorMessage method:

    public override string FormatErrorMessage(string name)
    {
        return $"{name} is invalid, must be between {_min} and {_max}";
    }

Difficult to say as I don't see line numbers and I'm not sure when exception is thrown. But you may to use TryParse instead of throwing exception and catching then.

int result;

if (double.TryParse(custBal.Text, out result))
{

            if (result< _min || result> _max)                
                return new ValidationResult(errorMessage); 
}
else
{
            return new ValidationResult(error);

}
Krzysztof Madej
  • 32,704
  • 10
  • 78
  • 107
  • Thanks for your answer but I believe that a validation has been done before it can reach my IsValid method. Do you have any idea? – anhtv13 Feb 07 '22 at 10:55
  • Could you tell which line you got this exception? – Krzysztof Madej Feb 07 '22 at 11:11
  • No it doesn't throw exception. The thing is when I click Send from Postman then I get straight away the message saying "Could not convert string to double: test. Path 'TestClass.TestNumber', line 36, position 22.". The debug point in constructor of TestAttribute is not hit. So I believe there must be a validation somewhere. – anhtv13 Feb 07 '22 at 11:20
  • It may be an issue with bind value. Could you take a look on this and try similar approach? https://stackoverflow.com/a/59322077/2347999 – Krzysztof Madej Feb 07 '22 at 11:28
0

As per my understanding, I believe you have developed a WebApi and trying to pass data using PostMan. The error you have posted is rejected by .Net framework because of its type safety feature. Since you are passing 'string' instead of 'double'.

Considering, you are accepting data for model 'TestClass' using 'FormBody' or by passing any JSON or XML string object.

The best way is to Validate the input data by an if condition before assigning it to the Model 'TestClass'. If it contains string then your custom message.

Hope this will solve your query.

  • You are understanding right. But I'm not clear the 3rd paragraph. Could you please explain in more details? Thanks. – anhtv13 Feb 07 '22 at 14:36
  • In the Action Result, before assigning to the property (TestNumber), just check with the below if condition (pseudocode for reference) double _testNumber = 0; //will hold value returned by TryParse //Note: '_value' variable in parameter of TryParse should be replaced with FormBody's value for TestNumber property. if (Double.TryParse(_value, out _testNumber)) {         // Assign the value to the model } else {       // return with your customized error message } – Sreekumar Pillai Feb 07 '22 at 18:38
  • The thing is that the TestClass is the parameter of a method in Controller. It's automatically mapped when I send the request. – anhtv13 Feb 08 '22 at 01:54