1+ // Licensed to the .NET Foundation under one or more agreements.
2+ // The .NET Foundation licenses this file to you under the MIT license.
3+
4+ using System ;
5+ using System . Collections . Generic ;
6+ using System . ComponentModel . DataAnnotations ;
7+ using Microsoft . AspNetCore . Builder ;
8+ using Microsoft . AspNetCore . Http ;
9+ using Microsoft . Extensions . DependencyInjection ;
10+ using Microsoft . Extensions . Validation ;
11+
12+ var builder = WebApplication . CreateSlimBuilder ( ) ;
13+
14+ builder . Services . AddValidation ( ) ;
15+
16+ var app = builder . Build ( ) ;
17+
18+ // Validation endpoints with different validatable types
19+ app . MapGet ( "/customers/{id}" , ( [ Range ( 1 , int . MaxValue ) ] int id ) =>
20+ $ "Getting customer with ID: { id } ") ;
21+
22+ app . MapPost ( "/customers" , ( Customer customer ) =>
23+ TypedResults . Created ( $ "/customers/{ customer . Id } ", customer ) ) ;
24+
25+ app . MapPost ( "/orders" , ( Order order ) =>
26+ TypedResults . Created ( $ "/orders/{ order . OrderId } ", order ) ) ;
27+
28+ app . MapPost ( "/products" , ( Product product ) =>
29+ TypedResults . Ok ( new ProductResponse ( "Product created" , product ) ) ) ;
30+
31+ app . MapPut ( "/addresses/{id}" , ( int id , Address address ) =>
32+ TypedResults . Ok ( new AddressResponse ( $ "Address { id } updated", address ) ) ) ;
33+
34+ app . MapPost ( "/users" , ( User user ) =>
35+ TypedResults . Created ( $ "/users/{ user . Id } ", user ) ) ;
36+
37+ app . MapPost ( "/inventory" , ( [ EvenNumber ] int productId , [ Required ] string name ) =>
38+ TypedResults . Ok ( new InventoryResponse ( productId , name ) ) ) ;
39+
40+ // Endpoint with disabled validation
41+ app . MapPost ( "/products/bulk" , ( Product [ ] products ) =>
42+ TypedResults . Ok ( new BulkProductResponse ( "Bulk products created" , products . Length ) ) )
43+ . DisableValidation ( ) ;
44+
45+ app . Run ( ) ;
46+
47+ return 100 ;
48+
49+ public class Customer
50+ {
51+ [ Required ]
52+ [ Range ( 1 , int . MaxValue ) ]
53+ public int Id { get ; set ; }
54+
55+ [ Required ]
56+ [ StringLength ( 100 , MinimumLength = 2 ) ]
57+ public string Name { get ; set ; } = string . Empty ;
58+
59+ [ EmailAddress ]
60+ public string Email { get ; set ; } = string . Empty ;
61+
62+ [ Range ( 18 , 120 ) ]
63+ [ Display ( Name = "Customer Age" ) ]
64+ public int Age { get ; set ; }
65+
66+ // Complex property with nested validation
67+ public Address Address { get ; set ; } = new ( ) ;
68+ }
69+
70+ public record Product (
71+ [ Required ] string Name ,
72+ [ Range ( 0.01 , double . MaxValue ) ] decimal Price ,
73+ [ StringLength ( 500 ) ] string Description = ""
74+ )
75+ {
76+ [ Required ]
77+ public string Category { get ; set ; } = string . Empty ;
78+ }
79+
80+ public class Address
81+ {
82+ [ Required ]
83+ [ StringLength ( 200 ) ]
84+ public string Street { get ; set ; } = string . Empty ;
85+
86+ [ Required ]
87+ [ StringLength ( 100 ) ]
88+ public string City { get ; set ; } = string . Empty ;
89+
90+ [ Required ]
91+ [ RegularExpression ( @"^\d{5}(-\d{4})?$" , ErrorMessage = "Invalid ZIP code format" ) ]
92+ public string ZipCode { get ; set ; } = string . Empty ;
93+
94+ [ StringLength ( 2 , MinimumLength = 2 ) ]
95+ public string State { get ; set ; } = string . Empty ;
96+ }
97+
98+ public class Order : IValidatableObject
99+ {
100+ [ Required ]
101+ public string OrderId { get ; set ; } = string . Empty ;
102+
103+ [ Required ]
104+ public int CustomerId { get ; set ; }
105+
106+ [ Range ( 0.01 , double . MaxValue ) ]
107+ public decimal Total { get ; set ; }
108+
109+ public DateTime OrderDate { get ; set ; } = DateTime . Now ;
110+
111+ public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
112+ {
113+ if ( OrderDate > DateTime . Now . AddDays ( 1 ) )
114+ {
115+ yield return new ValidationResult (
116+ "Order date cannot be more than 1 day in the future." ,
117+ new [ ] { nameof ( OrderDate ) } ) ;
118+ }
119+
120+ if ( Total > 10000 && CustomerId == 0 )
121+ {
122+ yield return new ValidationResult (
123+ "High-value orders require a valid customer ID." ,
124+ new [ ] { nameof ( CustomerId ) , nameof ( Total ) } ) ;
125+ }
126+ }
127+ }
128+
129+ public record User (
130+ [ Required ] [ StringLength ( 50 ) ] string Username ,
131+ [ EmailAddress ] string Email ,
132+ [ Phone ] string PhoneNumber = ""
133+ )
134+ {
135+ [ Required ]
136+ [ Range ( 1 , int . MaxValue ) ]
137+ public int Id { get ; set ; }
138+
139+ [ StringLength ( 100 ) ]
140+ public string DisplayName => $ "{ Username } ({ Email } )";
141+
142+ [ CreditCard ]
143+ public string CreditCardNumber { get ; set ; }
144+ }
145+
146+ // Custom validation attribute
147+ public class EvenNumberAttribute : ValidationAttribute
148+ {
149+ protected override ValidationResult IsValid ( object value , ValidationContext validationContext )
150+ {
151+ if ( value is int number && number % 2 != 0 )
152+ {
153+ return new ValidationResult ( "The number must be even." , new [ ] { validationContext . MemberName } ) ;
154+ }
155+
156+ return ValidationResult . Success ;
157+ }
158+ }
159+
160+ public record ProductResponse ( string Message , Product Product ) ;
161+
162+ public record AddressResponse ( string Message , Address Address ) ;
163+
164+ public record InventoryResponse ( int ProductId , string Name ) ;
165+
166+ public record BulkProductResponse ( string Message , int Count ) ;
0 commit comments