diff --git a/NorthwindCRUD/Controllers/CategoriesController.cs b/NorthwindCRUD/Controllers/CategoriesController.cs index d1c2143..bf61678 100644 --- a/NorthwindCRUD/Controllers/CategoriesController.cs +++ b/NorthwindCRUD/Controllers/CategoriesController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -50,8 +51,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetCategoriesWithSkip")] public ActionResult> GetCategoriesWithSkip( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/CustomersController.cs b/NorthwindCRUD/Controllers/CustomersController.cs index e040572..756149b 100644 --- a/NorthwindCRUD/Controllers/CustomersController.cs +++ b/NorthwindCRUD/Controllers/CustomersController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -50,8 +51,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetCustomersWithSkip")] public ActionResult> GetCustomersWithSkip( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/EmployeesController.cs b/NorthwindCRUD/Controllers/EmployeesController.cs index f220dd0..a7b20bf 100644 --- a/NorthwindCRUD/Controllers/EmployeesController.cs +++ b/NorthwindCRUD/Controllers/EmployeesController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -68,8 +69,8 @@ public ActionResult GetAllAuthorized() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetEmployeesWithSkip")] public ActionResult> GetPagedEmployees( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/OrdersController.cs b/NorthwindCRUD/Controllers/OrdersController.cs index 039d9cd..e247d03 100644 --- a/NorthwindCRUD/Controllers/OrdersController.cs +++ b/NorthwindCRUD/Controllers/OrdersController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -56,8 +57,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetPagedOrders")] public ActionResult> GetAllOrders( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/ProductsController.cs b/NorthwindCRUD/Controllers/ProductsController.cs index 0315470..e66ac19 100644 --- a/NorthwindCRUD/Controllers/ProductsController.cs +++ b/NorthwindCRUD/Controllers/ProductsController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -70,8 +71,8 @@ public ActionResult GetAllAuthorized() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetPagedProducts")] public ActionResult> GetAllProducts( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try @@ -267,7 +268,7 @@ public ActionResult Create(ProductDto model) } catch (InvalidOperationException exception) { - return StatusCode(400, exception.Message); + return StatusCode(400, exception.Message); } catch (Exception error) { diff --git a/NorthwindCRUD/Controllers/RegionsController.cs b/NorthwindCRUD/Controllers/RegionsController.cs index 0d16f13..7fde371 100644 --- a/NorthwindCRUD/Controllers/RegionsController.cs +++ b/NorthwindCRUD/Controllers/RegionsController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -50,8 +51,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetPagedRegions")] public ActionResult> GetAllRegions( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/ShippersController.cs b/NorthwindCRUD/Controllers/ShippersController.cs index 9924c2c..0a28356 100644 --- a/NorthwindCRUD/Controllers/ShippersController.cs +++ b/NorthwindCRUD/Controllers/ShippersController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -50,8 +51,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetPagedShippersWithSkip")] public ActionResult> GetPagedShippersWithSkip( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/SuppliersController.cs b/NorthwindCRUD/Controllers/SuppliersController.cs index 0914ed9..c8b65e6 100644 --- a/NorthwindCRUD/Controllers/SuppliersController.cs +++ b/NorthwindCRUD/Controllers/SuppliersController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -50,8 +51,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetPagedSuppliers")] public ActionResult> GetAllSuppliers( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Controllers/TerritoriesController.cs b/NorthwindCRUD/Controllers/TerritoriesController.cs index 05f160d..e96ba59 100644 --- a/NorthwindCRUD/Controllers/TerritoriesController.cs +++ b/NorthwindCRUD/Controllers/TerritoriesController.cs @@ -1,5 +1,6 @@ namespace NorthwindCRUD.Controllers { + using System.ComponentModel.DataAnnotations; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -52,8 +53,8 @@ public ActionResult GetAll() /// A PagedResultDto object containing the fetched T and the total record count. [HttpGet("GetPagedTerritories")] public ActionResult> GetAllTerritories( - [FromQuery][Attributes.SwaggerSkipParameter] int? skip, - [FromQuery][Attributes.SwaggerTopParameter] int? top, + [FromQuery][Attributes.SwaggerSkipParameter][Range(0, int.MaxValue)] int? skip, + [FromQuery][Attributes.SwaggerTopParameter][Range(0, int.MaxValue)] int? top, [FromQuery][Attributes.SwaggerOrderByParameter] string? orderBy) { try diff --git a/NorthwindCRUD/Models/Dtos/AddressDto.cs b/NorthwindCRUD/Models/Dtos/AddressDto.cs index fbef3b4..9713165 100644 --- a/NorthwindCRUD/Models/Dtos/AddressDto.cs +++ b/NorthwindCRUD/Models/Dtos/AddressDto.cs @@ -5,17 +5,23 @@ namespace NorthwindCRUD.Models.Dtos { public class AddressDto : IAddress { + [StringLength(100, ErrorMessage = "Street cannot exceed 100 characters.")] public string Street { get; set; } + [StringLength(50, ErrorMessage = "City cannot exceed 50 characters.")] public string City { get; set; } + [StringLength(50, ErrorMessage = "Region cannot exceed 50 characters.")] public string Region { get; set; } + [StringLength(20, ErrorMessage = "Postal code cannot exceed 20 characters.")] public string PostalCode { get; set; } [Required(ErrorMessage = "Country is required.")] + [StringLength(50, ErrorMessage = "Country cannot exceed 50 characters.")] public string Country { get; set; } + [RegularExpression(@"^\+?[1-9]\d{1,14}$", ErrorMessage = "Phone number is not valid.")] public string? Phone { get; set; } } } diff --git a/NorthwindCRUD/Models/Dtos/CategoryDetailsDto.cs b/NorthwindCRUD/Models/Dtos/CategoryDetailsDto.cs index 36b590c..62e0d41 100644 --- a/NorthwindCRUD/Models/Dtos/CategoryDetailsDto.cs +++ b/NorthwindCRUD/Models/Dtos/CategoryDetailsDto.cs @@ -5,6 +5,7 @@ namespace NorthwindCRUD.Models.Dtos { public class CategoryDetailsDto : CategoryDto, ICategoryDetail { + [RegularExpression(@"^(http[s]?://.*\.(?:jpg|jpeg|png|gif))$", ErrorMessage = "Picture URL must start with http/s and end with .jpg, .jpeg, .png, or .gif.")] public string Picture { get; set; } } } diff --git a/NorthwindCRUD/Models/Dtos/CategoryDto.cs b/NorthwindCRUD/Models/Dtos/CategoryDto.cs index 34b7158..ac04f4b 100644 --- a/NorthwindCRUD/Models/Dtos/CategoryDto.cs +++ b/NorthwindCRUD/Models/Dtos/CategoryDto.cs @@ -7,9 +7,11 @@ public class CategoryDto : ICategory { public int CategoryId { get; set; } + [StringLength(500, ErrorMessage = "Description cannot exceed 500 characters.")] public string Description { get; set; } [Required(ErrorMessage = "Name is required.")] + [StringLength(50, MinimumLength = 3, ErrorMessage = "Name must be between 3 and 50 characters.")] public string Name { get; set; } } } diff --git a/NorthwindCRUD/Models/Dtos/CustomerDto.cs b/NorthwindCRUD/Models/Dtos/CustomerDto.cs index ba10ed5..47a55ae 100644 --- a/NorthwindCRUD/Models/Dtos/CustomerDto.cs +++ b/NorthwindCRUD/Models/Dtos/CustomerDto.cs @@ -8,10 +8,13 @@ public class CustomerDto : ICustomer public string CustomerId { get; set; } [Required(ErrorMessage = "Company Name is required.")] + [StringLength(100, ErrorMessage = "Company Name cannot exceed 100 characters.")] public string CompanyName { get; set; } + [StringLength(50, ErrorMessage = "Contact Name cannot exceed 50 characters.")] public string ContactName { get; set; } + [StringLength(50, ErrorMessage = "Contact Title cannot exceed 50 characters.")] public string ContactTitle { get; set; } public AddressDto Address { get; set; } diff --git a/NorthwindCRUD/Models/Dtos/EmployeeDto.cs b/NorthwindCRUD/Models/Dtos/EmployeeDto.cs index 9d9ef3b..31c70c4 100644 --- a/NorthwindCRUD/Models/Dtos/EmployeeDto.cs +++ b/NorthwindCRUD/Models/Dtos/EmployeeDto.cs @@ -10,23 +10,29 @@ public class EmployeeDto : IEmployee public int EmployeeId { get; set; } [Required(ErrorMessage = "Last name is required.")] + [StringLength(50, ErrorMessage = "Last name cannot exceed 50 characters.")] [SwaggerSchema("Employee's last name.")] public string LastName { get; set; } + [StringLength(50, ErrorMessage = "First name cannot exceed 50 characters.")] [SwaggerSchema("Employee's first name.")] public string FirstName { get; set; } + [StringLength(50, ErrorMessage = "Title cannot exceed 50 characters.")] [SwaggerSchema("Employee's title")] public string Title { get; set; } + [StringLength(50, ErrorMessage = "Title of courtesy cannot exceed 50 characters.")] [SwaggerSchema("Title used in salutations")] public string TitleOfCourtesy { get; set; } [DataType(DataType.Date, ErrorMessage = "BirthDate must be a valid date.")] + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] [SwaggerSchema("Employee's birth date")] public string BirthDate { get; set; } [DataType(DataType.Date, ErrorMessage = "HireDate must be a valid date.")] + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] [SwaggerSchema("Employee's hire date")] public string HireDate { get; set; } @@ -34,12 +40,15 @@ public class EmployeeDto : IEmployee public AddressDto Address { get; set; } + [StringLength(1000, ErrorMessage = "Notes cannot exceed 1000 characters.")] [SwaggerSchema("General information about employee's background.")] public string Notes { get; set; } + [RegularExpression(@"^https?:\/\/.+\..+", ErrorMessage = "Avatar URL is not valid.")] [SwaggerSchema("Employee's avatar url.")] public string AvatarUrl { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "ReportsTo must be a valid employee ID.")] [SwaggerSchema("Employee's supervisor.")] public int ReportsTo { get; set; } } diff --git a/NorthwindCRUD/Models/Dtos/OrderDetailDto.cs b/NorthwindCRUD/Models/Dtos/OrderDetailDto.cs index f370893..b008471 100644 --- a/NorthwindCRUD/Models/Dtos/OrderDetailDto.cs +++ b/NorthwindCRUD/Models/Dtos/OrderDetailDto.cs @@ -9,8 +9,10 @@ public class OrderDetailDto public int ProductId { get; set; } + [Range(0.01, double.MaxValue, ErrorMessage = "Unit price must be greater than 0.")] public double UnitPrice { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "Quantity must be at least 1.")] public int Quantity { get; set; } public float Discount { get; set; } diff --git a/NorthwindCRUD/Models/Dtos/OrderDto.cs b/NorthwindCRUD/Models/Dtos/OrderDto.cs index 66a52bd..da6c9d8 100644 --- a/NorthwindCRUD/Models/Dtos/OrderDto.cs +++ b/NorthwindCRUD/Models/Dtos/OrderDto.cs @@ -11,20 +11,26 @@ public class OrderDto : IOrder [Required(ErrorMessage = "CustomerId is required.")] public string? CustomerId { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "EmployeeId must be a valid employee ID.")] public int EmployeeId { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "ShipperId must be a valid shipper ID.")] public int? ShipperId { get; set; } [DataType(DataType.Date, ErrorMessage = "OrderDate must be a valid date.")] + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] public string OrderDate { get; set; } [DataType(DataType.Date, ErrorMessage = "RequiredDate must be a valid date.")] + [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] public string RequiredDate { get; set; } public Shipping? ShipVia { get; set; } + [Range(0, double.MaxValue, ErrorMessage = "Freight must be a non-negative value.")] public double Freight { get; set; } + [StringLength(100, ErrorMessage = "ShipName cannot exceed 100 characters.")] public string ShipName { get; set; } public bool Completed { get; set; } diff --git a/NorthwindCRUD/Models/Dtos/ProductDto.cs b/NorthwindCRUD/Models/Dtos/ProductDto.cs index 9cf8d37..83f5bf4 100644 --- a/NorthwindCRUD/Models/Dtos/ProductDto.cs +++ b/NorthwindCRUD/Models/Dtos/ProductDto.cs @@ -1,4 +1,5 @@ -using NorthwindCRUD.Models.Contracts; +using System.ComponentModel.DataAnnotations; +using NorthwindCRUD.Models.Contracts; namespace NorthwindCRUD.Models.Dtos { @@ -8,18 +9,25 @@ public class ProductDto : IProduct public string ProductName { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "SupplierId must be a valid supplier ID.")] public int? SupplierId { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "CategoryId must be a valid category ID.")] public int? CategoryId { get; set; } + [StringLength(100, ErrorMessage = "QuantityPerUnit cannot exceed 100 characters.")] public string QuantityPerUnit { get; set; } + [Range(0, double.MaxValue, ErrorMessage = "UnitPrice must be a non-negative value.")] public double? UnitPrice { get; set; } + [Range(0, 1000000000, ErrorMessage = "UnitsInStock must be a non-negative value.")] public int? UnitsInStock { get; set; } + [Range(0, 1000000, ErrorMessage = "UnitsOnOrder must be a non-negative value.")] public int? UnitsOnOrder { get; set; } + [Range(0, int.MaxValue, ErrorMessage = "ReorderLevel must be a non-negative value.")] public int? ReorderLevel { get; set; } public bool Discontinued { get; set; } diff --git a/NorthwindCRUD/Models/Dtos/SalesDto.cs b/NorthwindCRUD/Models/Dtos/SalesDto.cs index 0ee7277..d554dce 100644 --- a/NorthwindCRUD/Models/Dtos/SalesDto.cs +++ b/NorthwindCRUD/Models/Dtos/SalesDto.cs @@ -7,8 +7,10 @@ public class SalesDto [Required(ErrorMessage = "ProductId is required.")] public int ProductId { get; set; } + [Range(1, int.MaxValue, ErrorMessage = "QuantitySold must be at least 1.")] public int QuantitySold { get; set; } + [Range(0.01, 1000000, ErrorMessage = "SaleAmount must be greater than 0.")] public double SaleAmount { get; set; } } } diff --git a/NorthwindCRUD/Models/Dtos/ShipperDto.cs b/NorthwindCRUD/Models/Dtos/ShipperDto.cs index a01c71c..283b215 100644 --- a/NorthwindCRUD/Models/Dtos/ShipperDto.cs +++ b/NorthwindCRUD/Models/Dtos/ShipperDto.cs @@ -8,8 +8,10 @@ public class ShipperDto : IShipper public int ShipperId { get; set; } [Required(ErrorMessage = "Company Name is required.")] + [StringLength(100, ErrorMessage = "Company Name cannot exceed 100 characters.")] public string CompanyName { get; set; } + [RegularExpression(@"^\+?[1-9]\d{1,14}$", ErrorMessage = "Phone number is not valid.")] public string Phone { get; set; } } } diff --git a/NorthwindCRUD/Models/Dtos/SupplierDto.cs b/NorthwindCRUD/Models/Dtos/SupplierDto.cs index a96b0e1..6916760 100644 --- a/NorthwindCRUD/Models/Dtos/SupplierDto.cs +++ b/NorthwindCRUD/Models/Dtos/SupplierDto.cs @@ -8,26 +8,37 @@ public class SupplierDto : ISupplier public int SupplierId { get; set; } [Required(ErrorMessage = "Company Name is required.")] + [StringLength(100, ErrorMessage = "Company Name cannot exceed 100 characters.")] public string? CompanyName { get; set; } + [StringLength(100, ErrorMessage = "Contact Name cannot exceed 100 characters.")] public string? ContactName { get; set; } + [StringLength(50, ErrorMessage = "Contact Title cannot exceed 50 characters.")] public string? ContactTitle { get; set; } + [StringLength(250, ErrorMessage = "Address cannot exceed 250 characters.")] public string? Address { get; set; } + [StringLength(50, ErrorMessage = "City cannot exceed 50 characters.")] public string? City { get; set; } + [StringLength(50, ErrorMessage = "Region cannot exceed 50 characters.")] public string? Region { get; set; } + [StringLength(20, ErrorMessage = "Postal Code cannot exceed 20 characters.")] public string? PostalCode { get; set; } + [StringLength(50, ErrorMessage = "Country cannot exceed 50 characters.")] public string? Country { get; set; } + [RegularExpression(@"^\+?[1-9]\d{1,14}$", ErrorMessage = "Phone number is not valid.")] public string? Phone { get; set; } + [RegularExpression(@"^\+?[1-9]\d{1,14}$", ErrorMessage = "Fax number is not valid.")] public string? Fax { get; set; } + [RegularExpression(@"^https?:\/\/[^\s$.?#].[^\s]*$", ErrorMessage = "Home Page URL is not valid.")] public string? HomePage { get; set; } } }