0

If I have an MVC model that (grossly simplified) looks like this;

public class Person
{

    [Required]
    public string SpecialSauce { get; set; }

    [Required]
    public string Name { get; set; }

}

However, only the Name comes from the view. The SpecialSauce is provided server side.

person.SpecialSauce = "Ketchup"; //Hard-coded for example

However, before I save, I check ModelState.IsValid, which returns false, with the error "The SpecialSauce field is required."

How do I make the ModelState valid when the required model property is provided server side? I could remove the [Required] data annotation, but I want the EF database column to be non-nullable.

n00b
  • 4,341
  • 5
  • 31
  • 57
  • 6
    use viewmodel instead of your db class and dont add required attribute this time sauce property. – Murat Can OĞUZHAN Feb 06 '18 at 16:47
  • So I need a seperate model for the view? This is very basic, and would seem a shame to require a seperate model, but if thats the standard practice... – n00b Feb 06 '18 at 16:48
  • 1
    Remove `[Required]` attribute from the model but configure db mapping using [EF Fluent API](http://www.entityframeworktutorial.net/code-first/configure-property-mappings-using-fluent-api.aspx). Also it would be better to create a viemodel to separate concerns. – Roman Koliada Feb 06 '18 at 16:51
  • you are need to second resolution at that time or you can write your validate attribute and control it. https://stackoverflow.com/questions/20642328/how-to-put-conditional-required-attribute-into-class-property-to-work-with-web-a – Murat Can OĞUZHAN Feb 06 '18 at 16:54
  • or exclude it https://stackoverflow.com/questions/2142990/the-id-field-is-required-validation-message-on-create-id-not-set-to-required – Murat Can OĞUZHAN Feb 06 '18 at 16:57
  • If `person.SpecialSauce` is set only in the `HttpPost` why can't it be set in the `HttpGet` method and then return the `person` object to the view? – Grizzly Feb 06 '18 at 17:00
  • This is one of the (many) reasons for ViewModels. Use [AutoMapper](http://automapper.org/) to ease the process. – Steve Greene Feb 06 '18 at 17:03

1 Answers1

1

Frankly, not quite sure how you expect SpecialSauce to be required but yet not allow the user to enter a value for SpecialSauce on the form and then you override it in the controller.

But.. here is an answer if SpecialSauce needs to be required.

Since you are setting person.SpecialSauce on the server side, you should set it in the HttpGet Method. Then return the entire object back to the View. If you don't want a user editing that field, then disable it via HTML or jQuery.

Here is an example:

Controller

// GET: ControllerName/Create
public ActionResult Create()
{
    var myPerson = new Person()
    {
        SpecialSauce = "Ketchup"
    };

    return View(myPerson); // assuming your view is named Create and it is expecting an object of type Person.
}

View

@model Project.Models.Person // top of view

@Html.HiddenFor(model => model.SpecialSauce) // you can't submit disabled items to the server so create a HiddenField to hold the actual value for submission

@Html.TextBoxFor(model => model.SpecialSauce, null, new { @class = "form-control", @disabled = "disabled" }) // the textbox on page load should contain "Ketchup" and be disabled so the user can't edit the string

Then, your ModelState will be valid and then you don't have to set it in the HttpPost action method.

Let me know if this helps.

Grizzly
  • 5,873
  • 8
  • 56
  • 109
  • I think I am begining to realize the convention is to have a model specific to your view, and a seperate one specific to the database as in my case "special sauce" is the result of a lookup on the persons name. The tutorial i went through on MVC did not talk about this distinction. – n00b Feb 06 '18 at 17:16
  • 1
    @n00b In that case, a ViewModel would be appropriate and then look into AutoMapper for easy mapping of properties instead of having to manually write each one. – Grizzly Feb 06 '18 at 17:17
  • 1
    You will run into an overposting problem with this. since you are defining specialsauce in your model, anyone can post a value to SpecialSauce using fiddler/postman/... Also disabled input items are not sent back to the server in a POST. Use a view model. – Fran Feb 06 '18 at 18:30
  • 1
    @Fran good point about not being able to submit disabled items. I updated my answer to reflect a HiddenFor for the submission. I do agree with the ViewModel approach. My answer was just based on the information I was given. – Grizzly Feb 06 '18 at 19:35
  • Leaving this as the selected answer, since you answered the question, but I agree in the end, I need a view model. – n00b Mar 13 '18 at 13:46
  • Hidden fields can be seen in the html source of the page so make sure never to store sensitive data there. – Jamshaid K. Oct 20 '18 at 23:15