0

I have a model with some validations below

        public class RequestABook
        {
            [Required(ErrorMessage = "Name Required")]
            [DisplayName("Book Name")]
            public string BookName { get; set; }

            [Required(ErrorMessage = "Zipcode Required")]
            [DisplayName("Zipcode")]
            public string ZipCode { get; set; }

            [Required(ErrorMessage = "Contact Name Required")]
            [DisplayName("Contact Name")]
            public string ContactName { get; set; }

            [Required(ErrorMessage = "Email Id Required")]
            [DataType(DataType.EmailAddress)]
            public string Email { get; set; }

            [Required(ErrorMessage = "Book Description Required")]
            public string BookDescription { get; set; }

            [Required(ErrorMessage = "You need to check one answer")]
            public string Answer { get; set; }
        }

I have a view model here

        public class RequestViewModel
        {
            public RequestABook MyTestViewModel { get; set; }   
        }

I have my main page here that loads

        @model BookRequestValidation.Models.RequestViewModel

        @{
            ViewBag.Title = "RequestABook";
        }

        <h2>RequestABook</h2>

        @using (Html.BeginForm())
        {
            @Html.ValidationSummary(true)
            <fieldset>
                <legend>Request Book</legend>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MyTestViewModel.BookName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MyTestViewModel.BookName)
                    @Html.ValidationMessageFor(m => m.MyTestViewModel.BookName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MyTestViewModel.ZipCode)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MyTestViewModel.ZipCode)
                    @Html.ValidationMessageFor(m => m.MyTestViewModel.ZipCode)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MyTestViewModel.ContactName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MyTestViewModel.ContactName)
                    @Html.ValidationMessageFor(m => m.MyTestViewModel.ContactName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MyTestViewModel.Email)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MyTestViewModel.Email)
                    @Html.ValidationMessageFor(m => m.MyTestViewModel.Email)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MyTestViewModel.BookDescription)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MyTestViewModel.BookDescription)
                    @Html.ValidationMessageFor(m => m.MyTestViewModel.BookDescription)
                </div>

                <div id="HCBudget" class="validation">
                    <label for="budgethealth">Budget Health</label>
                    @Html.RadioButton("Answer", "Red")
                    @Html.RadioButton("Answer", "Yellow")
                    @Html.RadioButton("Answer", "Green")  
                    @Html.ValidationMessageFor(m => m.MyTestViewModel.Answer)   
                </div>

                <input type="submit" value="Request Book" />
            </fieldset> 
            } 

Question: How do you guys handle validation with models used in a viewmodel. Before I used this in a viewmodel everything was working well. By the time I used a viewmodel validation stopped working.

Here is what the post action looks like.

        public ActionResult RequestABook()
        {
            return View();
        }

        [HttpPost]
        public ActionResult RequestABook(RequestABook quote)
        {
            return View();
        }
Baba
  • 2,059
  • 8
  • 48
  • 81
  • The model in the view is `RequestViewModel` so the POST method must match `public ActionResult RequestABook(RequestViewModel quote)` (or use the `Prefix` property of `BindAttribute`). But this is not a view model. Its just a model that contains a property which is a data model and is bad practice (as is adding view specific attributes to data models). Refer [What is ViewModel in MVC?](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc). –  Jun 07 '16 at 01:03
  • Thanks. I will read the link right away. – Baba Jun 07 '16 at 11:50

1 Answers1

0

It would help greatly if you posted your POST action. However, generally, I can say that validation is only run on related class instances if they are non-null. So, unless a value is posted for at least one of the properties on MyTestViewModel, it will not be instantiated by the modelbinder (MyTestViewModel will be null), and validation on its properties will not be run.

You can fix this scenario by always instantiating the MyTestViewModel property, either via the constructor of your view model or, probably better, using a custom getter and setter:

  1. Constructor

    public class RequestViewModel
    {
        public RequestViewModel()
        {
            MyTestViewModel = new RequestABook();
        }
    
        ...
    }
    
  2. Custom Getter and Setter

    private RequestABook myTestViewModel;
    public RequestABook MyTestViewModel
    {
        get
        {
            if (myTestViewModel == null)
            {
                myTestViewModel = new RequestABook();
            }
            return myTestViewModel;
        }
        set { myTestViewModel = value; }
    }
    
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444