0

Im new to asp.net MVC4 , I have an MVC4 application that is using SQL Server 2012 EntityFramework (code first). The Edit post method is not saving the data. On checking if ModelState.IsValid it return false, can anyone help me find whats wrong with my code

MODEL

public class Customer
    {
        [Key]
        public int Id { get; set; }
    [Required(ErrorMessage="*")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "*")]
    public string LastName { get; set; }

    [Required(ErrorMessage = "*")]
    [MaxLength(1, ErrorMessage="Initial only")]
    public string MI { get; set; }

    [Required(ErrorMessage = "*")]
    public string Address { get; set; }

    [Required(ErrorMessage = "*")]
    public String ContactNo { get; set; }

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

    [Required(ErrorMessage = "*")]
    [MaxLength(8, ErrorMessage = "Max of 8")]
    [MinLength(5, ErrorMessage = "Min of 5")]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    [NotMapped]
    public string Password { get; set; }

    [Required(ErrorMessage = "*")]
    [DataType(DataType.Password)]
    [NotMapped]
    [Display(Name = "Retype-PW")]
    public string RetypePassword { get; set; }

    [Required]       
    [Display(Name = "How much is")]
    [NotMapped]
    public string Captcha { get; set; }
}

EDIT VIEW

<h2>Edit CUSTOMER</h2>
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Customer</legend>

        @Html.HiddenFor(model => model.Id)
        @Html.HiddenFor(model=>model.Captcha)
        @Html.HiddenFor(model=>model.Password)
        @Html.HiddenFor(model=>model.RetypePassword)

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.MI)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MI)
            @Html.ValidationMessageFor(model => model.MI)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address)
            @Html.ValidationMessageFor(model => model.Address)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ContactNo)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ContactNo)
            @Html.ValidationMessageFor(model => model.ContactNo)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.EmailAddress)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.EmailAddress)
            @Html.ValidationMessageFor(model => model.EmailAddress)
        </div>        
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

EDIT CONTROLLER METHOD

public ActionResult Edit(int id = 0)
        {
            Customer customer = db.Customers.Find(id);
            if (customer == null)
            {
                return HttpNotFound();
            }
            return View(customer);
        }

        //
        // POST: /Customer/Edit/5

        [HttpPost]
        public ActionResult Edit(Customer customer)
        {
            if (ModelState.IsValid)
            {
                db.Entry(customer).State = EntityState.Modified;
                db.SaveChanges();
                if (User.IsInRole("Administrator"))
                {
                    return RedirectToAction("Index");
                }
                else
                {
                    return RedirectToAction("Details");
                }

            }
            return View(customer);
        }

Thanks for the help

PgE92
  • 13
  • 2
  • 8
  • Without your form input, it's impossible to know what was invalid. So take look at this SO answer that tells you how to identify the cause of invalid state: http://stackoverflow.com/a/1791664/2777098 – display name Nov 27 '14 at 18:12
  • Thanks :) your suggestion really help me a lot. i put the validation message for the this @Html.HiddenFor(model=>model.Captcha) @Html.HiddenFor(model=>model.Password) @Html.HiddenFor(model=>model.RetypePassword) and it shows that it has a null value when submitting the form thats why the ModelState is return not valid. – PgE92 Nov 27 '14 at 18:29

3 Answers3

1
@Html.HiddenFor(model=>model.Captcha)
@Html.HiddenFor(model=>model.Password)
@Html.HiddenFor(model=>model.RetypePassword)

this lines are not safety, it's possible view the content in console at the same time maybe isn't the good value in password you make a 8 char limit but you read the value in bd, i hope this value is cripted!, you write a code to more to 8 char well the model isn't valid, try to read the value for this champs in the console and compare with your settings.

the problem you use the same model to create and edit, well for edit isn't required the captha and pasword, the options are make other model, setting not required, check if create or edit mode to set required,

chefjuanpi
  • 1,570
  • 15
  • 27
  • The 3 property(Captcha, password, retypepassword) of my model is sit to notmapped. These are unmapped because I save password as byte array and using captcha when customer signing up. – PgE92 Nov 27 '14 at 18:59
  • my other question is If property Password, Captcha, retypepassword are explicitly annitated as [NotMapped], why is EF validating it during save? – PgE92 Nov 27 '14 at 19:02
  • EF is not validating during save, those `[Required]` annotations are also used by the ModelState validation. – CodeCaster Nov 27 '14 at 19:10
0

help me find whats wrong with my code

  • You're using the scaffolded @Html.ValidationSummary(true), where true is passed for hidePropertyErrors. This is fine if your edit form shows an editor for each property of your model, but if not, your page will not show what ModelState errors prevented successful processing. Change true to false to see all errors.
  • You're using Entity Framework models as ViewModels.
  • You're allowing mass assignment.
  • You're not using an cross-site request forgery token.

You've just run into the prime case that demonstrates why you should use ViewModels. One solution is to remove model errors for properties you don't want to see as faulty.

Like:

ModelState.Remove("Captcha");
ModelState.Remove("Password");
ModelState.Remove("RetypePassword");

if (ModelState.IsValid)
{
    // your code ...

But this will cause your model to be updated with an empty password null for the properties for which you didn't provide an editor, which you don't want to and which will fail anyway. So you'll need to load the existing entity and update it:

ModelState.Remove("Captcha");
ModelState.Remove("Password");
ModelState.Remove("RetypePassword");

if (ModelState.IsValid)
{
    var existingCustomer = db.Customers.First(c => c.ID == customer.ID);

    // Update properties of attached entity
    existingCustomer.FirstName = customer.FirstName;
    existingCustomer.LastName = customer.LastName;
    // and so on...

To circumvent most of this clumsiness, simply define a ViewModel:

public class EditCustomerModel
{
    [Required(ErrorMessage="*")]
    public string FirstName { get; set; }

    [Required(ErrorMessage="*")]
    public string LastName { get; set; }

    // and so on...
}

Then in your action method will look like this:

public ActionResult Edit(EditCustomerModel customer)
{
    if (ModelState.IsValid)
    {
        var existingCustomer = db.Customers.First(c => c.ID == customer.ID);

        // Update properties of attached entity
        existingCustomer.FirstName = customer.FirstName;
        existingCustomer.LastName = customer.LastName;

        db.SaveChanges();

        return RedirectToAction(...);
    }

    return View();
}
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • ERROR: Validation failed for one or more entities – PgE92 Nov 27 '14 at 19:58
  • That's unfortunate, but with such little detail I hardly can be of help. I gave a few suggestions in my answer and don't know which you implemented and how. – CodeCaster Nov 27 '14 at 20:00
0

I used CodeCaster 2nd suggestion but it didn't work, but when I put hidden input for my 3 notmapped fields(Captcha, password, retypepassword) on my view and assigning default values it works now.

<input type="hidden" id="Captcha" name="Captcha" value="Captcha" />
<input type="hidden" id="Password" name="Password" value="Password" />
<input type="hidden" id="RetypePassword" name="RetypePassword" value="RetypePassword" />
PgE92
  • 13
  • 2
  • 8