liveBook · Manning

Range attribute

As explained in Pro ASP.NET Core 7, Tenth Edition

The Range attribute is a .NET validation attribute that restricts a value to a specified lower and upper bound.

The Range attribute declares numeric bounds as model metadata, keeping invalid values out of the application before an action stores or processes the bound object. section 29.5 section 19.5.4

Use the attribute where the model needs a bounded value:

  • Apply [Range(1, 1000)] to a decimal Price property to reject values outside the inclusive lower and upper limits. section 19.5.4 section 29.5
  • Apply [Range(1, long.MaxValue)] to identifier properties whose default zero value should not be accepted when the client omits them. section 19.5.4
  • Supply ErrorMessage when the default response is too vague, such as [Range(1, 999999, ErrorMessage = "Please enter a positive price")]. section 29.5
  • Use the attribute with numeric values or property types implementing IComparable; boolean constraints can also use Range with typeof(bool). section 29.5

Rejecting an incomplete product request

A ProductBindingTarget can constrain Price, CategoryId, and SupplierId with Range attributes. The POST action checks ModelState.IsValid before converting the target, saving it, and returning Ok; invalid input returns BadRequest(ModelState). Posting only {"Name":"Boot Laces"} produces range errors because the primitive properties remain zero. section 19.5.4

Listing 29.15 Applying validation attributes in the Product.cs file in the Models folder
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace WebApp.Models {
    public class Product {
        
        public long ProductId { get; set; }
        [Required(ErrorMessage = "Please enter a name")]
        public required string Name { get; set; }
                
        [Range(1, 999999, ErrorMessage = "Please enter a positive price")]
        [Column(TypeName = "decimal(8, 2)")]
        public decimal Price { get; set; }
                
        public long CategoryId { get; set; }
        public Category? Category { get; set; }
                
        public long SupplierId { get; set; }
                
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public Supplier? Supplier { get; set; }
    }
}

Inspect the complete Product model showing a bounded Price property alongside its database column configuration and custom validation message. section 29.5

How Pro ASP.NET Core 7, Tenth Edition covers it

How deep it goes
Defines inclusive bounds, supported comparable types, custom messages, and ModelState handling, but does not detail validator internals.
Examples
Uses bounded product prices and identifiers, a boolean checkbox constraint, a POST request, and returned validation errors.
What it assumes
Assumes basic model binding and controller actions while teaching bounded validation through model attributes and ModelState checks.
What you can do after
Apply it via ASP.NET Core MVC attributes, inspect ModelState, and return BadRequest instead of persisting invalid bound objects.
How it connects
Connects model binding, model validation, ModelState, Required, action methods, and HTTP 400 responses.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Pro ASP.NET Core 7, Tenth Edition. The section links point to the parts of the book it draws on.