Invalid model state in Posting data with form in MVC5

5.2k Views Asked by At

I'm completely new in Asp.net MVC

I want to fill a form and post it to data base but my model Binder validation is false . and my Errors which I have in my model doesn't show

I'm sorry because I don't know what is the problem I couldn't shorten it:

here is my model:

public class Request
{
    //pkey
    public virtual int Id { get; set; }
    //Fkey
    public virtual int TourId { get; set; }

    [Required]
    [MaxLength(150, ErrorMessageResourceType = typeof(ErrorResource), ErrorMessageResourceName = "CheckLenght")]
    public virtual string FirstName { get; set; }


    [Required]
    [MaxLength(150, ErrorMessageResourceType = typeof(ErrorResource), ErrorMessageResourceName = "CheckLenght")]
    public virtual string LastName { get; set; }

    [Required]
    [EmailAddress(ErrorMessageResourceType = typeof(ErrorResource), ErrorMessageResourceName = "Email")]
    [MaxLength(150, ErrorMessageResourceType = typeof(ErrorResource), ErrorMessageResourceName = "CheckLenght")]
    public virtual string Email { get; set; }

    [Required]
    public virtual string Phone { get; set; }

    [MaxLength(100000000, ErrorMessageResourceType = typeof(ErrorResource), ErrorMessageResourceName = "CheckLenght")]
    public virtual string Comment { get; set; }


    public virtual bool FrequentTraveler { get; set; }

    [Required]
    [Range(1, 500000)]
    public virtual int TravelersCount { get; set; }


    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
    public virtual string Date { get; set; }


    public virtual bool ContactTimePreference { get; set; }

    [MaxLength(150, ErrorMessageResourceType = typeof(ErrorResource), ErrorMessageResourceName = "CheckLenght")]
    public virtual string Country { get; set; }


    public virtual bool Archived { get; set; }

and this is my form in view :

@using (Html.BeginForm("Create", "Request"))
{
  <div class="form-group">
   <input  type="hidden" name="TourId" value="4"/>
  </div>

 <div class="form-group">
 @Html.EditorFor(model => model.Request.FirstName, new { htmlAttributes = new { @class = "form-control" } })
 @Html.ValidationMessageFor(model => model.Request.FirstName, "", new { @class = "text-danger" , placeholder = "FirstName" })

 </div>



<div class="form-group">
 @Html.EditorFor(model => model.Request.LastName, new { htmlAttributes = new { @class = "form-control" } })
 @Html.ValidationMessageFor(model => model.Request.LastName, "", new { @class = "text-danger" })
</div>


<div class="form-group">                                       
@Html.EditorFor(model => model.Request.Email, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Request.Email, "", new { @class = "text-danger" })
</div>

<div class="form-group">
 @Html.EditorFor(model => model.Request.Phone, new { htmlAttributes = new { @class = "form-control" } })
 @Html.ValidationMessageFor(model => model.Request.Phone, "", new { @class = "text-danger" })
</div>


 <div class="form-group ft">
 @Html.EditorFor(model => model.Request.FrequentTraveler)
 @Html.ValidationMessageFor(model => model.Request.FrequentTraveler, "", new { @class = "text-danger" })
    </div>


<div class="form-group">
   <input type="hidden" name="TravelersCount" value="3" />
</div>

  <div class="form-group">
    <input type="hidden" name="TravelersCount" value="3" />
  </div>



}

I omit some of the form groups which they allow to be null for shorthand.

and this is my create action in Request controller:

 [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "Id,TourId,FirstName,LastName,Email,Phone,Comment,FrequentTraveler,TravelersCount,Date,ContactTimePreference,Country,Archived")] Request request)
    {
        if (ModelState.IsValid)
        {
            db.Requests.Add(request);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View();
    }

I appreciate if some one tell me what is the problem to make my request object valid.and if its possible what to do to send Errors to user when for example they put null in first name which its required with server.

2

There are 2 best solutions below

0
AudioBubble On BEST ANSWER

ModelState will be invalid because your view is generating form controls for a model which is different from the model that you expect in the POST method. For example

@Html.EditorFor(model => model.Request.FirstName, ...)

is generating

<input type="text" name="Request.FirstName" .... />

but the model in the POST method is Request which does not have a property named Request - it only has one named FirstName so binding fails and ModelState is invalid because of the [Required] validation attribute.

In order to bind to a Request model, the html would need to be

<input type="text" name="FirstName" .... />

In addition, your [Bind] attribute is also excluding the values from correctly binding since it does include "Request".

Remove the [Bind] attribute (you seem to be wanting to bind everything anyway which is the default) and either change the model in the POST method to match the model you declared in the view, or use the Prefix property of BindAttribute

public ActionResult Create([Bind(Prefix= "Request")] Request model)

and finally delete the manually html for the hidden inputs and use @Html.HiddenFor(m => m.Request.TourId) etc so that the name attributes are consistent and will correctly bind.

Finally, I recommend you read What is ViewModel in MVC?. Using data models in your views, particularly when editing forms is poor practice.

Side note: You can use the following query in your POST methods to easily check the properties of your model that have validation errors

var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0).Select(k => new
{
    propertyName = k,
    errorMessage = ModelState[k].Errors[0].ErrorMessage
});
1
ProgrammerV5 On

You shouldn't use the same name as the parameter as the model name, that will break the binding process on the way back. Try to change the signature from

public ActionResult Create(Request request)

to

public ActionResult Create(Request req)

To check for the ModelState errors use the following code:

foreach (ModelState modelState in ViewData.ModelState.Values)
{
 foreach (ModelError error in modelState.Errors)
 {
    var xx = error.ErrorMessage;
 }
}

If you put a breakpoint on var xx you will see what the error is but I'm pretty sure it's because there is no proper binding because of the names you used (In fact I will change the name Request for something else entirely but that's just me).

Hope this helps.