public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } var modelType = bindingContext.ModelType; if (modelType != typeof(Date) && modelType != typeof(Date?)) { throw new InvalidOperationException($"Cannot bind {modelType.Name}."); } var dayModelName = $"{bindingContext.ModelName}.{DayComponentName}"; var monthModelName = $"{bindingContext.ModelName}.{MonthComponentName}"; var yearModelName = $"{bindingContext.ModelName}.{YearComponentName}"; var dayValueProviderResult = bindingContext.ValueProvider.GetValue(dayModelName); var monthValueProviderResult = bindingContext.ValueProvider.GetValue(monthModelName); var yearValueProviderResult = bindingContext.ValueProvider.GetValue(yearModelName); // If all components are empty and ModelType is nullable then bind null to result if (dayValueProviderResult == ValueProviderResult.None && monthValueProviderResult == ValueProviderResult.None && yearValueProviderResult == ValueProviderResult.None) { if (modelType == typeof(Date?)) { bindingContext.Result = ModelBindingResult.Success(null); } else { bindingContext.Result = ModelBindingResult.Failed(); } return(Task.CompletedTask); } int day = -1; int month = -1; int year = -1; bool yearIsValid = false, monthIsValid = false, dayIsValid = false; if ((yearIsValid = TryParseYear()) && (monthIsValid = TryParseMonth()) && (dayIsValid = TryParseDay())) { var date = new Date(year, month, day); bindingContext.Result = ModelBindingResult.Success(date); } else { bindingContext.ModelState.SetModelValue(dayModelName, dayValueProviderResult); bindingContext.ModelState.SetModelValue(monthModelName, monthValueProviderResult); bindingContext.ModelState.SetModelValue(yearModelName, yearValueProviderResult); DateParseErrorComponents errorComponents = DateParseErrorComponents.None | (!dayIsValid ? DateParseErrorComponents.Day : DateParseErrorComponents.None) | (!monthIsValid ? DateParseErrorComponents.Month : DateParseErrorComponents.None) | (!yearIsValid ? DateParseErrorComponents.Year : DateParseErrorComponents.None); bindingContext.ModelState.TryAddModelError( bindingContext.ModelName, new DateParseException("Invalid date specified.", errorComponents), bindingContext.ModelMetadata); bindingContext.Result = ModelBindingResult.Failed(); } return(Task.CompletedTask); bool TryParseDay() { if (dayValueProviderResult != ValueProviderResult.None && dayValueProviderResult.FirstValue != string.Empty) { if (!int.TryParse(dayValueProviderResult.FirstValue, out day) || day < 1 || (month != -1 && year != -1 && day > DateTime.DaysInMonth(year, month))) { bindingContext.ModelState.TryAddModelError( dayModelName, "Day is not valid."); bindingContext.ModelState.TryGetValue(bindingContext.ModelName, out var x); return(false); } else { return(true); } } else { bindingContext.ModelState.TryAddModelError( dayModelName, "Day is missing."); return(false); } } bool TryParseMonth() { if (monthValueProviderResult != ValueProviderResult.None && monthValueProviderResult.FirstValue != string.Empty) { if (!int.TryParse(monthValueProviderResult.FirstValue, out month) || month < 1 || month > 12) { bindingContext.ModelState.TryAddModelError( monthModelName, "Month is not valid."); return(false); } else { return(true); } } else { bindingContext.ModelState.TryAddModelError( monthModelName, "Month is missing."); return(false); } } bool TryParseYear() { if (yearValueProviderResult != ValueProviderResult.None && yearValueProviderResult.FirstValue != string.Empty) { if (!int.TryParse(yearValueProviderResult.FirstValue, out year) || year < 1 || year > 9999) { bindingContext.ModelState.TryAddModelError( yearModelName, "Year is not valid."); return(false); } else { return(true); } } else { bindingContext.ModelState.TryAddModelError( yearModelName, "Year is missing."); return(false); } } }
internal DateParseException(string message, DateParseErrorComponents errorComponents) : base(message) { ErrorComponents = errorComponents; }