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?

HappyTown
  • 6,036
  • 8
  • 38
  • 51
  • I think you can use Range attribute in this case. No need to implement custom validation for this. Hope to help, my friend! – Tomato32 Aug 16 '18 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. – HappyTown Aug 16 '18 at 17:16
  • 1
    Possible duplicate of [use decimal values as attribute params in c#?](https://stackoverflow.com/questions/507528/use-decimal-values-as-attribute-params-in-c) – Jonathon Chase Aug 16 '18 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. – Jonathon Chase Aug 16 '18 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. – HappyTown Aug 16 '18 at 17:38

3 Answers3

3

Use Range attribute. Also works great for decimals too.

[Range(0.01, 99999999)]
Tommix
  • 443
  • 4
  • 15
  • This was made possible in .NET Core. src: Validation attributes https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-6.0#validation-attributes – Tyson Gibby Jun 25 '23 at 08:21
3

Try following code:

[Range(1, int.MaxValue, ErrorMessage = "Value Must Bigger Than {1}")]
AliNajafZadeh
  • 1,216
  • 2
  • 13
  • 22
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;
        }
    }
Levi Fuller
  • 13,631
  • 4
  • 38
  • 44
HappyTown
  • 6,036
  • 8
  • 38
  • 51
  • 2
    By convention, all attribute classes should be suffixed `Attribute`. – Paulo Morgado Aug 16 '18 at 20:30
  • 1
    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. – Paulo Morgado Aug 16 '18 at 20:34
  • @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. – HappyTown Aug 17 '18 at 14:16
  • 1
    Acceptable up until you are bitten by it. One is stored as base 2 an the other as base 10. – Paulo Morgado Aug 17 '18 at 19:49