Steven Lemmens
Steven Lemmens

Reputation: 720

Custom model binder fires and runs, but property value is never bound

I wrote a custom model binder that will take the value of two textboxes (containing 'Date' and 'Time') and create a DateTime object from these two values.

My ModelBinder fires, runs succesfully and correctly parses the input into a valid DateTime, and when my Action gets called with the Model, the property StartDateTime equals ´DateTime.MinValue` instead of what was parsed in the ModelBinder.

My simplified Model looks like this:

[ModelBinder(BinderType = typeof(DateTimeModelBinder))]
[Required]
public DateTime StartDateTime { get; set; }

This is my ModelBinder, which fires and runs correctly:

public Task BindModelAsync(ModelBindingContext bindingContext)
{
    if (bindingContext == null)
       throw new ArgumentException(nameof(bindingContext));

    var modelName = bindingContext.ModelName;
    var dateName = $"{modelName}.Date";
    var timeName = $"{modelName}.Time";

    string dateValue = TryGetValue(ref bindingContext, dateName); //function omitted for brevity, but it works!
    string timeValue = TryGetValue(ref bindingContext, timeName);

    bool dateIsValid = DateTime.TryParse(dateValue, out DateTime dateTime);
    bool timeIsValid = TimeSpan.TryParse(timeValue, out TimeSpan timeOfDayResult);

    if (dateIsValid && timeIsValid)
    {
       ModelBindingResult.Success(new DateTime(dateTime.Year, dateTime.Month, dateTime.Day,
                    timeOfDayResult.Hours, timeOfDayResult.Minutes, timeOfDayResult.Seconds));
    }

    return Task.CompletedTask;
}

And then when I enter my Action, the StartDateTime property has no value set

public IActionResult Detail(ActivityEditModel model)
{
   var startTime = model.StartDateTime; //property equals DateTime.MinValue, instead of the parsed value from the model binder above
}

Upvotes: 0

Views: 17

Answers (1)

Steven Lemmens
Steven Lemmens

Reputation: 720

This was the eventual solution:

In the ModelBinder, you need to set the bindingContext.Result to success and this is how I should have done it:

bindingContext.Result = ModelBindingResult.Success(new DateTime(dateTime.Year, dateTime.Month, dateTime.Day,
                    timeOfDayResult.Hours, timeOfDayResult.Minutes, timeOfDayResult.Seconds));

Upvotes: 0

Related Questions