user256034
user256034

Reputation: 4369

Required attribute for an integer value

I have a viewmodel with an Id property

[Required]
public int Id { get; set; }

But I think this attribute is working only for string properties.

When no Id is set, Id has value 0 and the model is valid.

How can I enforce that if no value for a int property is set, the model will be invalid ?

Upvotes: 80

Views: 56357

Answers (6)

Marked as Duplicate
Marked as Duplicate

Reputation: 1249

There is a potential solution that gets past the limitations of [BindRequired], works with all value types (+ integers where zero is a valid value), and doesn't require you to make all your ints nullable.

  • For simple cases, use [BindRequired].
  • When you also need to bind data from the body (JSON), use the required keyword.
  • If you want the model errors that JSON binding produces to be good, create a custom value provider.
  • And if you need custom property-specific error messages and/or want to make all non-nullable value types required by default, implement a custom model binder.

https://thom.ee/blog/clean-way-to-use-required-value-types-in-asp-net-core/

The implementation is a bit long, but easily copy-pastable. The final result is that you can get your input models working like this:

[Required(ErrorMessage = "Optional error message")]
public int Id { get; set; }

Upvotes: 1

Dominik Kozioł
Dominik Kozioł

Reputation: 21

If you are using a database, you should use the attributes [Key] and [DatabaseGenerated(DatabaseGenerated.Identity)] and Id shouldn't be NULLABLE.

Upvotes: 0

David Berg
David Berg

Reputation: 2058

This is similar to the answer from @Lee Smith, but enables 0 to be valid input, which might be useful in some scenarios.

What you can do is to init the int value to another value then 0, like this:

[Range(0, int.MaxValue)]
public int value{ get; set; } = -1;

It would even be possible to support all values except int.MinValue by doing it like this:

[Range(int.MinValue + 1, int.MaxValue)]
public int value{ get; set; } = int.MinValue;

Upvotes: 5

Dustin C
Dustin C

Reputation: 265

For .NET Core (and maybe earlier versions) you can also create a custom attribute to perform the range validation for ease of reuse:

public class Id : ValidationAttribute
{
    protected override ValidationResult IsValid(
        object value,
        ValidationContext validationContext)
    {
        return Convert.ToInt32(value) > 0 ?
            ValidationResult.Success :
            new ValidationResult($"{validationContext.DisplayName} must be an integer greater than 0.");
    }
}

Use the Id attribute like this in your model:

public class MessageForUpdate
{
    [Required, Id]
    public int UserId { get; set; }
    [Required]
    public string Text { get; set; }
    [Required, Id]
    public int ChannelId { get; set; }
}

When the Id is <= 0 this error message is returned:

UserId must be an integer greater than 0.

No need to verify that the value is less than int.MaxValue (although it is nice to display that in the message) because the API will return this error by default before it gets this far even if the value is int.MaxValue + 1:

The JSON value could not be converted to System.Int32

Upvotes: 6

Lee Smith
Lee Smith

Reputation: 6747

Use the Range Attribute.

Set minimum to 1 and maximum to int.MaxValue

[Range(1, int.MaxValue, ErrorMessage = "Value for {0} must be between {1} and {2}.")]

Upvotes: 120

Julien Lebosquain
Julien Lebosquain

Reputation: 41243

Change the type to Nullable<int> (shortcut int?) to allow null values.

Upvotes: 56

Related Questions