Jaylen Jaylen - 2 months ago 16
ASP.NET (C#) Question

Is it possible to make a property nullable and required at the same time in ASP.NET MVC 5 ViewModel?

I have the following view model

public class FormViewModel
{
[Required]
public DateTime? LocalFrom { get; set; }

[Required]
public DateTime? LocalTo { get; set; }
}


then in the controller I have the following action

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index([Bind(Include = "LocalFrom,LocalTo")] FormViewModel model)
{
if (ModelState.IsValid)
{
var presenter = new ManagePresenter(model);
return View(presenter);
}
return View(model); // here model.LocalFrom, model.LocalTo should be null
}


Here is my HTML form

<form class="form-horizontal" action="/Manage/Index" method="post">

@Html.AntiForgeryToken()
<div class="form-group">
<label class="control-label col-sm-2" for="LocalFrom">From</label>
<div class="col-sm-10">
<input type="datetime" class="form-control" id="LocalFrom" name="LocalFrom" value="@Model.LocalFrom" required>
</div>
</div>

<div class="form-group">
<label class="control-label col-sm-2" for="LocalTo">To</label>
<div class="col-sm-10">
<input type="datetime" class="form-control" id="LocalTo" name="LocalTo" value="@Model.LocalTo)" required>
</div>
</div>

<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>

</form>


I am not sure if making nullable property required is logical or not here. I basically want to populate the input with the name
LocalFrom
in the view with
blank
when
Model.LocalFrom
is null or with the correct value when
Model.LocalFrom
is not null.

Problem

Then
ModelState.IsValid
is always returning false even we all the required values are present and valid.

When I make
LocalFrom
and
LocalTo
not nullable I the
ModelState
becomes valid. but in the view will display the time of the beginning of time like so

enter image description here

How can I pass null value to the view and make the ModelState to validate correctly?

Answer

If you want to allow null values, then you need to remove the [Required] attribute from your DateTime properties. A [Required] attribute means that the value cannot be null so if you submit an empty value (null) then ModelState will be invalid.

Removing the attributes means that submitting a valid date or null will be valid, but submitting an invalid date will still result in ModelState being invalid.

In addition, you generating your html manually, and as a result you are not getting correct 2-way model binding (which is why you see the default value for DateTime when you return the view). Your view should be

<div class="form-group">
    @Html.LabelFor(m => m.LocalFrom, new { @class="control-label col-sm-2" }) // assumes you add [Display(Name = "From")] to the property
    <div class="col-sm-10">
        @Html.TextBoxFor(m => m.LocalFrom)
        @Html.ValidationMessageFor(m => m.LocalFrom)
    </div>
</div>

As a side note, you should remove the unnecessary [Bind] attribute. Your using a view model, which means your already protected from over-posting attacks.

Finally, include the jquery.validate.js and jquery.validate.unobtrusive.js scripts in your view so that you get client side validation that matches your server side validation attributes and the appropriate error message is displayed in the view.

Comments