我有这个模型:
public class CalendarAvailabilityRequest
{
[Required]
[FromQuery]
public DateTime StartDate { get; set; }
}
以及此控制器/操作方法:
[ApiController]
[Route("api/[controller]")]
public class AppointmentController : ControllerBase
{
[Route("{providerName}/CalendarAvailability")]
[HttpGet]
public Task<CalendarAvailabilityResponse> GetCalendarAvailability(CalendarAvailabilityRequest request)
{
return null;
}
}
在到达端点时,如何确定仅接受"yyyy-MM-dd"
?
例如这将被接受:
https://example.org/api?StartDate=2019-04-17
但是这些会引发异常:
https://example.org/api?StartDate=2019-17-04
https://example.org/api?StartDate=17-04-2017
答案 0 :(得分:1)
我建议您使用fluentvalidation,因为它可以分离并重复使用验证规则。
在您假设startdate
是CalendarAvailabilityRequest
一部分的情况下,您将为请求dto添加一个验证器:
public class CalendarAvailabilityRequestValidator :
AbstractValidator<CalendarAvailabilityRequest>
{
public CalendarAvailabilityRequestValidator()
{
RuleFor(request => request.StartDate)
.Must(BeAValidDateFormat).WithMessage("Date must follow the format: yyyy-mm-dd")
.NotNull().WithMessage("A start date must be provided.");
}
// will only match yyyy-mm-dd
private static bool BeAValidDateFormat(string date)
=> Regex.IsMatch(date, "2\d{3}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$", RegexOptions.Compiled);
}
在您的控制器内,实例化一个验证器,并使其验证:
[Route("{providerName}/CalendarAvailability")]
[HttpGet]
public Task<IActionResult> GetCalendarAvailability(CalendarAvailabilityRequest request)
{
var validationResult = new CalendarAvailabilityRequestValidator().Validate(request);
if (!validationResult.IsValid)
{
Log.Warning(validationResult.Errors.ToString());
return BadRequest(validationResult.Errors);
}
var statDate = DateTime.ParseExact(request.StartDate, "yyyy-mm-dd", CultureInfo.InvariantCulture);
//TODO: calendar availability logic
return OK();
}
当然,您也可以从上方使用 regex 并在控制器中验证请求。
另一种选择是尝试使用DateTime.ParseExact
这样的捕获:
try
{
var statDate = DateTime.ParseExact(request.StartDate, "yyyy-mm-dd", CultureInfo.InvariantCulture);
}
catch(exception ex)
{
Log.Warning("Request for {startdate} was invalid: {message}", request.StartDate, ex.Message);
return BadRequest(ex.message);
}
但是我建议您在可以验证输入时避免尝试catch,除非您确实需要。
答案 1 :(得分:1)
我最终写了一个实现Attribute
的{{1}}:
IResourceFilter
我将该属性应用于了我的操作方法:
public class DateTimeResourceFilterAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
const string PreferredDateTimeFormat = "yyyy-MM-dd";
string dateTimeString = context.HttpContext.Request.Query["StartDate"].First();
bool isPreferredDateTimeFormat = DateTime.TryParseExact(dateTimeString, PreferredDateTimeFormat, new CultureInfo("en-AU"), DateTimeStyles.None, out DateTime dateTime);
if (!isPreferredDateTimeFormat)
{
context.Result = new ContentResult()
{
Content = $"Date must be in the following format: {PreferredDateTimeFormat}",
StatusCode = (int)HttpStatusCode.BadRequest
};
}
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}