ASP.NET Core Web API:如何使用Fluent Validation验证start_date与end_date的格式为yyyy-MM-dd
ASP.NET Core Web API:如何使用Fluent Validation验证start_date与end_date的格式为yyyy-MM-dd
我理解你现在的需求——已经用Fluent Validation完成了基本的非空校验和日期大小比较,现在要额外确保start_date和end_date必须严格遵循yyyy-MM-dd的格式。这里给你两种实用的解决方案,你可以根据项目情况选择:
方案一:保持现有DateTime模型,校验原始输入格式
如果不想修改现有模型结构,我们可以通过验证上下文获取原始请求中的日期字符串,来做严格的格式校验:
步骤1:更新验证器
修改EmployeeHistoryRequestValidator,为日期字段添加自定义格式校验规则:
using System.Globalization; using FluentValidation; public class EmployeeHistoryRequestValidator : AbstractValidator<EmployeeHistoryRequest> { public EmployeeHistoryRequestValidator() { // 原有员工编码校验规则 RuleFor(p => p.employee_code) .NotNull().WithMessage("Employee Code cannot be null") .NotEmpty().WithMessage("Employee Code field is required. ERROR!"); // 开始日期校验:非空 + 格式验证 RuleFor(p => p.start_date) .NotNull().WithMessage("Start Date cannot be null") .Must((model, startDate, context) => { // 从上下文获取原始请求中的start_date字符串 if (context.RootContextData.TryGetValue("start_date", out var rawValue) && rawValue is string rawDate) { // 严格匹配yyyy-MM-dd格式 return DateTime.TryParseExact(rawDate, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _); } // 无法获取原始值则视为格式不合法 return false; }) .WithMessage("Start Date must be in the format yyyy-MM-dd (e.g., 2019-08-24)"); // 结束日期校验:和开始日期逻辑一致 RuleFor(p => p.end_date) .NotNull().WithMessage("End Date cannot be null") .Must((model, endDate, context) => { if (context.RootContextData.TryGetValue("end_date", out var rawValue) && rawValue is string rawDate) { return DateTime.TryParseExact(rawDate, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _); } return false; }) .WithMessage("End Date must be in the format yyyy-MM-dd (e.g., 2019-08-24)"); // 原有日期大小比较规则 RuleFor(x => x) .Must(x => x.end_date > x.start_date) .WithMessage("End Date must be greater than Start Date"); } }
步骤2:在Controller中传递原始请求数据
在处理请求的Action里,需要把原始请求中的日期字符串传递给验证上下文:
using Microsoft.AspNetCore.Mvc; using System.Text.Json; [ApiController] [Route("api/[controller]")] public class EmployeeController : ControllerBase { [HttpPost("history")] public async Task<IActionResult> SubmitEmployeeHistory([FromBody] EmployeeHistoryRequest request) { // 读取原始请求的JSON数据 var rawRequest = await JsonSerializer.DeserializeAsync<dynamic>(HttpContext.Request.Body); // 创建验证上下文并传入原始日期值 var validationContext = new ValidationContext<EmployeeHistoryRequest>(request); validationContext.RootContextData["start_date"] = rawRequest.start_date; validationContext.RootContextData["end_date"] = rawRequest.end_date; // 执行验证 var validator = new EmployeeHistoryRequestValidator(); var validationResult = validator.Validate(validationContext); if (!validationResult.IsValid) { return BadRequest(validationResult.Errors); } // 后续调用第三方API的业务逻辑 return Ok("Request validated successfully"); } }
方案二:将模型日期属性改为string,直接校验格式(更简洁)
如果允许调整模型结构,这种方案会更直观——把日期属性改为string类型,先验证格式,再转换为DateTime供后续使用:
步骤1:修改模型
using System.Globalization; public class EmployeeHistoryRequest { public string employee_code { get; set; } public string start_date { get; set; } public string end_date { get; set; } // 提供转换后的DateTime属性,方便业务逻辑使用 public DateTime StartDate => DateTime.ParseExact(start_date, "yyyy-MM-dd", CultureInfo.InvariantCulture); public DateTime EndDate => DateTime.ParseExact(end_date, "yyyy-MM-dd", CultureInfo.InvariantCulture); }
步骤2:更新验证器
using System.Globalization; using FluentValidation; public class EmployeeHistoryRequestValidator : AbstractValidator<EmployeeHistoryRequest> { public EmployeeHistoryRequestValidator() { RuleFor(p => p.employee_code) .NotNull().WithMessage("Employee Code cannot be null") .NotEmpty().WithMessage("Employee Code field is required. ERROR!"); // 开始日期校验:非空 + 正则格式匹配 + 有效日期验证 RuleFor(p => p.start_date) .NotNull().WithMessage("Start Date cannot be null") .NotEmpty().WithMessage("Start Date should not be empty. ERROR!") .Matches(@"^\d{4}-\d{2}-\d{2}$").WithMessage("Start Date must be in the format yyyy-MM-dd") .Must(dateStr => DateTime.TryParseExact(dateStr, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _)) .WithMessage("Start Date is not a valid date (e.g., 2019-08-24 is valid, 2019-13-01 is invalid)"); // 结束日期校验:和开始日期逻辑一致 RuleFor(p => p.end_date) .NotNull().WithMessage("End Date cannot be null") .NotEmpty().WithMessage("End Date should not be empty. ERROR!") .Matches(@"^\d{4}-\d{2}-\d{2}$").WithMessage("End Date must be in the format yyyy-MM-dd") .Must(dateStr => DateTime.TryParseExact(dateStr, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _)) .WithMessage("End Date is not a valid date (e.g., 2019-08-24 is valid, 2019-13-01 is invalid)"); // 日期大小比较:转换为DateTime后判断 RuleFor(x => x) .Must(x => { DateTime.TryParseExact(x.start_date, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var start); DateTime.TryParseExact(x.end_date, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var end); return end > start; }) .WithMessage("End Date must be greater than Start Date"); } }
这种方案不需要额外处理原始请求,验证逻辑更清晰,推荐在可以修改模型的场景下使用。
备注:内容来源于stack exchange,提问作者Ayobamilaye
相关产品推荐
相关产品推荐

