ModelState errors not being displayed after changing Model

534 Views Asked by At

I'm following the NerdDinner example on Professional ASP.NET MVC 1.0 (I'm using the version of ASP.NET MVC that comes with VisualStudio 2015), and so far I was able to fix some little problems, but this one got me.

I have a model named Dinner, which is being passed to a view for an action called Create(). The view corresponding to Create is basically a form that asks for some information, and when it is submitted the page displays errors if there are any. The errors are communicated to the view through ModelState object.

    public ActionResult Create()
    {
        Dinner dinner = new Dinner();
        return View(dinner);
    }

    [HttpPost]
    public ActionResult Create(Dinner d)
    {
        TryUpdateModel(d);
        if (d.isValid)
        {
            ...
        }
        else
        {
            foreach (var violation in d.GetRuleViolations())
                ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage);
            return View(d);
        }
    }

Create view looks something like this.

@model NerdDinner.Models.Dinner

...

            @Html.ValidationMessageFor(Model => Model.Title, "", new { @class = "text-danger" })

...

This worked fine until I created a new model called DinnerFormViewModel to pass additional objects to Create view.

public class DinnerFormViewModel
{
    public Dinner Dinner
    {
        get;
        private set;
    }

    public DinnerFormViewModel() : this(new Dinner()) { }

    public DinnerFormViewModel(Dinner d)
    {
        Dinner = d;
    }

    ... stuff ...
}

I updated the Create() method to make sure I was passing the correct model to the corresponding view.

    public ActionResult Create()
    {
        Dinner dinner = new Dinner();
        return View(new DinnerFormViewModel(dinner));   // Updated line.
    }

    [HttpPost]
    public ActionResult Create(DinnerFormViewModel d)   // Updated line.
    {
        TryUpdateModel(d);
        if (d.Dinner.isValid)   // Updated line.
        {
            ...
        }
        else
        {
            foreach (var violation in d.Dinner.GetRuleViolations())   // Updated line.
                ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage);
            return View(new DinnerFormViewModel(d.Dinner));   // Updated line.
        }
    }

Also updated the view.

@model NerdDinner.Models.DinnerFormViewModel

...

            @Html.ValidationMessageFor(Model => Model.Dinner.Title, "", new { @class = "text-danger" })

...

The page functions as it should (valid form data is saved correctly), but when invalid information is submitted errors are not displayed on the page anymore. In the view file I checked the errors stored in ModelState and they were all there. There seems to be a disconnect between the ModelState and the form fields. I'm thinking the problem is the property names I am providing to ModelState.AddModelError() method, but I'm not sure about it. Any help is appreciated.

1

There are 1 best solutions below

2
Chris Pratt On

First, when you have a class instance property inside your model, if it's null, validation is not run on any of its properties. Second, your class instance property has a private setter, so the modelbinder will be unable to actually set it to anything, meaning it will always be null.

Long and short, the issue is the private setter.