locked
Why is the following code not working. RRS feed

  • Question

  • User-826336654 posted

    Hi All,

    It is a silly question but I need to know whether the code below is working as expected or something is wrong with it.

    I feel that it is NOT behaving as it should. Can anyone help me?

    Screen shot 1:

    I enter the following data.

    Model:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace WebApplication9.Models
    {
        public class Student
        {
            public int StudentId { get; set; }
    
            [Display(Name = "Full Name:")]
            public string FullName { get; set; }
    
            [Display(Name = "Email:")]
            public string Email { get; set; }
    
            [Display(Name = "Mobile:")]
            public string Mobile { get; set; }
    
            [Display(Name = "Telephone:")]
            public string Telephone { get; set; }
        }
    }

    Controller:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using WebApplication9.Models;
    
    namespace WebApplication9.Controllers
    {
        public class HomeController : Controller
        {
            // GET: Home
            public ActionResult Index()
            {
                return View();
            }
    
            [HttpPost, ValidateAntiForgeryToken]
            public ActionResult Index(Student student)
            {
                if (ModelState.IsValid)
                {
                    student.FullName = "John Taylor";
                }
    
                return View(student);
            }
        }
    }

    View:

    @model WebApplication9.Models.Student
    
    @{
        ViewBag.Title = "Index";
    }
    
    @using (Html.BeginForm()) 
    {
        @Html.AntiForgeryToken()
        
        <div class="form-horizontal">
            <h4>Student</h4>
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group">
                @Html.LabelFor(model => model.FullName, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.FullName, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.FullName, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Mobile, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Mobile, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Mobile, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                @Html.LabelFor(model => model.Telephone, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.Telephone, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.Telephone, "", new { @class = "text-danger" })
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
    
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
    

    Final Screen shot:

    After clicking the submit button, it still showing the same data but I have change the data. Everything is clearly evident in the screen shot.

    Thanks in advance

    Saturday, January 12, 2019 11:11 AM

Answers

  • User753101303 posted

    Hi,

    See https://patrickdesjardins.com/blog/modelstate-clear-is-required-to-display-back-your-model-object if you have to.

    Make sure  it makes sense. You are supposed to show a view following a POST if the validation fails and you want the user to keep trying again. If not you should use https://en.wikipedia.org/wiki/Post/Redirect/Get to show accepted data.

    It could be compared with a database that would change a value sent for an update statement. It doesn't change which values were sent for the update and the one that sent the update would know about this change only if the row is read (GET) again.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 2:20 PM
  • User475983607 posted

    After clicking the submit button, it still showing the same data but I have change the data. Everything is clearly evident in the screen shot.

    Correct and by design.  HTML helpers read the Model State which is populated by the model binding.   The model state error has the state of the model as submitted along with any errors.  This makes error handling easier.

    You can get past this by clearing the ModelState but that causes other design considerations. 

    ModelState.Clear()

    A POST action usually does an INSERT/UPDATE.  The result is commonly a redirect to listing or confirmation page.  IMHO, it is uncommon to face this situation in a real world application.  However, it easily found when testing.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 2:38 PM
  • User-826336654 posted

    Thanks mgebhard and PatriceSc,

    Thanks for the reply. Using ModelState.Clear() or ModelState.Remove("FullName") both are working. I am 200% sure that this question will be asked in my next project. So, good to find out that it is Correct and By Design. Just Change the Controller class a bit and changes are shown below for future reference.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using WebApplication9.Models;
    
    namespace WebApplication9.Controllers
    {
        public class HomeController : Controller
        {
            // GET: Home
            public ActionResult Index()
            {
                return View();
            }
    
            [HttpPost, ValidateAntiForgeryToken]
            public ActionResult Index(Student student)
            {
               
                if (ModelState.IsValid)
                {
                    student.FullName = "John Taylor";
                    //ModelState.Clear();
                    ModelState.Remove("FullName");
                }
    
                return View(student);
            }
        }
    }

    Thanks.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 3:20 PM
  • User475983607 posted

    Thanks for the reply. Using ModelState.Clear() or ModelState.Remove("FullName") both are working. I am 200% sure that this question will be asked in my next project. So, good to find out that it is Correct and By Design. Just Change the Controller class a bit and changes are shown below for future reference.

    Keep in mind, you approach injects a change after model validation.  You need to trust the process that changes the FullName.  It makes more sense to remove the property all together because it is not set by the user.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 3:29 PM
  • User753101303 posted

    I am 200% sure that this question will be asked in my next project.

    I came accross that when learning about MVC and never used that since then. It should at best be very rare. Keep in mind you are basically showing again the user the data he entered and there is little reason to change them to something else without his consent.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, January 13, 2019 1:26 PM

All replies

  • User1120430333 posted

    ASP.NET MVC uses a FormCollection  between the controller and the view. You changed the model object the view uses,  but the view itself didn't change the key value/pair in the FormCollection, becuase you did nothing in the view to change the value and post back 

    https://www.w3schools.com/asp/coll_form.asp

    Saturday, January 12, 2019 12:46 PM
  • User-826336654 posted

    DA924

    ASP.NET MVC uses a FormCollection  between the controller and the view. You changed the model object the view uses,  but the view itself didn't change the key value/pair in the FormCollection, becuase you did nothing i

    https://www.w3schools.com/asp/coll_form.asp

    Thanks for the reply. Can you please tell me, what should I do "in the view to change the value and post back "?

    Saturday, January 12, 2019 1:02 PM
  • User1120430333 posted

    DA924

    ASP.NET MVC uses a FormCollection  between the controller and the view. You changed the model object the view uses,  but the view itself didn't change the key value/pair in the FormCollection, becuase you did nothing i

    https://www.w3schools.com/asp/coll_form.asp

    Thanks for the reply. Can you please tell me, what should I do "in the view to change the value and post back "?

    I think the only thing you can do is enter some data into the control and push the Submit button and post back to the controller.  If there is a way to change the FormCollection from the controller, I don't know about it. You can Request a value from the Formcollection in the controller.

    Saturday, January 12, 2019 1:27 PM
  • User753101303 posted

    Hi,

    See https://patrickdesjardins.com/blog/modelstate-clear-is-required-to-display-back-your-model-object if you have to.

    Make sure  it makes sense. You are supposed to show a view following a POST if the validation fails and you want the user to keep trying again. If not you should use https://en.wikipedia.org/wiki/Post/Redirect/Get to show accepted data.

    It could be compared with a database that would change a value sent for an update statement. It doesn't change which values were sent for the update and the one that sent the update would know about this change only if the row is read (GET) again.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 2:20 PM
  • User475983607 posted

    After clicking the submit button, it still showing the same data but I have change the data. Everything is clearly evident in the screen shot.

    Correct and by design.  HTML helpers read the Model State which is populated by the model binding.   The model state error has the state of the model as submitted along with any errors.  This makes error handling easier.

    You can get past this by clearing the ModelState but that causes other design considerations. 

    ModelState.Clear()

    A POST action usually does an INSERT/UPDATE.  The result is commonly a redirect to listing or confirmation page.  IMHO, it is uncommon to face this situation in a real world application.  However, it easily found when testing.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 2:38 PM
  • User-826336654 posted

    Thanks mgebhard and PatriceSc,

    Thanks for the reply. Using ModelState.Clear() or ModelState.Remove("FullName") both are working. I am 200% sure that this question will be asked in my next project. So, good to find out that it is Correct and By Design. Just Change the Controller class a bit and changes are shown below for future reference.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using WebApplication9.Models;
    
    namespace WebApplication9.Controllers
    {
        public class HomeController : Controller
        {
            // GET: Home
            public ActionResult Index()
            {
                return View();
            }
    
            [HttpPost, ValidateAntiForgeryToken]
            public ActionResult Index(Student student)
            {
               
                if (ModelState.IsValid)
                {
                    student.FullName = "John Taylor";
                    //ModelState.Clear();
                    ModelState.Remove("FullName");
                }
    
                return View(student);
            }
        }
    }

    Thanks.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 3:20 PM
  • User475983607 posted

    Thanks for the reply. Using ModelState.Clear() or ModelState.Remove("FullName") both are working. I am 200% sure that this question will be asked in my next project. So, good to find out that it is Correct and By Design. Just Change the Controller class a bit and changes are shown below for future reference.

    Keep in mind, you approach injects a change after model validation.  You need to trust the process that changes the FullName.  It makes more sense to remove the property all together because it is not set by the user.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 12, 2019 3:29 PM
  • User1120430333 posted

    Thanks for the reply. Using ModelState.Clear() or ModelState.Remove("FullName") both are working. I am 200% sure that this question will be asked in my next project. So, good to find out that it is Correct and By Design. Just Change the Controller class a bit and changes are shown below for future reference.

    Frankly speaking, I don't see the point of this changing of the FormCollection value.  This is  business logic that should be happening on the VM or model  with an object in the Models folder and the VM or model sent back to the view. The controller IMO has no business doing this. .

    To me,  what you are doing is unorthodox and not following MVC principles.  

    Sunday, January 13, 2019 1:03 AM
  • User753101303 posted

    I am 200% sure that this question will be asked in my next project.

    I came accross that when learning about MVC and never used that since then. It should at best be very rare. Keep in mind you are basically showing again the user the data he entered and there is little reason to change them to something else without his consent.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, January 13, 2019 1:26 PM
  • User-826336654 posted

    Frankly speaking, I don't see the point of this changing of the FormCollection value.  This is  business logic that should be happening on the VM or model  with an object in the Models folder and the VM or model sent back to the view. The controller IMO has no business doing this. .

    To me,  what you are doing is unorthodox and not following MVC principles.  

    Thanks DA924, I am 100% with you but this was just an example as I am trying a few things. I am professional developer and always use multiple layer architecture. So, the question was not about MVC architecture but about why the code is behaving like that. I am 100% sure that I will never use this type of code in real world but sometimes questions do arise in the meetings. I am hoping that you understand where I am coming from thanks.

    Sunday, January 13, 2019 3:15 PM