2

I created a custom validator for an integer to check input greater than 0. It works fine.

Custom Validation for Integer

using System;
using System.ComponentModel.DataAnnotations;

public class GeaterThanInteger : ValidationAttribute
    {
        private readonly int _val;

        public GeaterThanInteger(int val)
        {
            _val = val;
        }   

        public override bool IsValid(object value)
        {
            if (value == null) return false;            
            return Convert.ToInt32(value) > _val;
        }       
    }

Calling code

[GeaterThanInteger(0)]
public int AccountNumber { get; set; }

Custom Validator for Decimal

I am trying to create similar validator for decimal to check input greater than 0. However I this time I ran in to compiler errors.

public class GreaterThanDecimal : ValidationAttribute
{
    private readonly decimal _val;

    public GreaterThanDecimal(decimal val)
    {
        _val = val;
    }

    public override bool IsValid(object value)
    {
        if (value == null) return false;
        return Convert.ToDecimal(value) > _val;
    }
}

Calling code

[GreaterThanDecimal(0)]
public decimal Amount { get; set; }

Compiler Error (points to the [GreaterThanDecimal(0)])

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

I tried few combinations,

[GreaterThanDecimal(0M)]
[GreaterThanDecimal((decimal)0)]

But does not work.

I looked through the ValidationAttribute definition and documentation, but I am still lost.

What is the error complaining about?

Is there any alternate way to validate Decimal greater than 0 in this case?

5
  • I think you can use Range attribute in this case. No need to implement custom validation for this. Hope to help, my friend! Commented Aug 16, 2018 at 17:10
  • @Tomato32 Thanks. But with Range I would need to define the min and max values. Defining the least min value which is greater 0 will be tricky, specially for decimals. Also I don't want to put the max limit constraint. That's why I was just trying to define it as - a decimal greater than 0. Commented Aug 16, 2018 at 17:16
  • 1
    Possible duplicate of use decimal values as attribute params in c#? Commented Aug 16, 2018 at 17:24
  • 1
    Is there any reason you can't use an double/int to set the initial value to compare against? If you're just checking if it's greater than 0, then your attribute could accept an integer parameter to compare against the decimal. Commented Aug 16, 2018 at 17:26
  • @JonathonChase Thanks. Reading from the link you shared - "Decimals while a basic type are not a primitive type and hence cannot be represented in metadata which prevents it from being an attribute parameter." - the error now totally makes sense. Yes, I can change it to double and it works. Commented Aug 16, 2018 at 17:38

3 Answers 3

6

Use Range attribute. Also works great for decimals too.

[Range(0.01, 99999999)]
Sign up to request clarification or add additional context in comments.

1 Comment

This was made possible in .NET Core. src: Validation attributes learn.microsoft.com/en-us/aspnet/core/mvc/models/…
4

Try following code:

[Range(1, int.MaxValue, ErrorMessage = "Value Must Bigger Than {1}")]

Comments

0

@JonathonChase answered it in the comments, I thought I would complete the answer with modified code sample here, in case someone stumbles upon this with the same problems.

What is the error complaining about?

Because the call [GreaterThanDecimal(0)] is trying to pass decimal as an attribute parameter, this is not supported by CLR. See use decimal values as attribute params in c#?

Solution

Change the parameter type to double or int

public class GreaterThanDecimalAttribute : ValidationAttribute
    {
        private readonly decimal _val;


        public GreaterThanDecimalAttribute(double val) // <== Changed parameter type from decimal to double
        {
            _val = (decimal)val;
        }

        public override bool IsValid(object value)
        {
            if (value == null) return false;
            return Convert.ToDecimal(value) > _val;
        }
    }

4 Comments

By convention, all attribute classes should be suffixed Attribute.
The precision of double is not the same as the precision of decimal. You might run into surprises. You should have the same constructor overloads on your attribute as on the decimal struct to be on the safe side.
@PauloMorgado, losing some precision is acceptable in my use case. Having ctor(decimal) and ctor(double) both side by side, compiler would complain that the call between the two is ambiguous.
Acceptable up until you are bitten by it. One is stored as base 2 an the other as base 10.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.